From 0509175a57c19d061c97d4e709bd5ae7afbd8ff6 Mon Sep 17 00:00:00 2001 From: wangziqi Date: Thu, 9 Jul 2026 16:08:53 +0800 Subject: [PATCH] feat: add getDeptDepthMap BFS method for org tree depth tracking --- .../src/integration/dingtalk.service.ts | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/apps/server/src/integration/dingtalk.service.ts b/apps/server/src/integration/dingtalk.service.ts index 224b001..dd1f99c 100644 --- a/apps/server/src/integration/dingtalk.service.ts +++ b/apps/server/src/integration/dingtalk.service.ts @@ -262,6 +262,42 @@ export class DingTalkService { return ids; } + /** + * BFS from rootDeptId=1, returns depth of every department. + * Depth is 1-based (root=1). Uses listsubid API only, no detail fetches. + */ + private async getDeptDepthMap(token: string): Promise> { + const depthMap = new Map(); + const queue: Array<{ id: number; depth: number }> = [{ id: 1, depth: 1 }]; + + while (queue.length > 0) { + const { id, depth } = queue.shift()!; + depthMap.set(id, depth); + + try { + await this.rateLimit(); + const res = await fetch( + `https://oapi.dingtalk.com/topapi/v2/department/listsubid?access_token=${token}`, + { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ dept_id: id }), + }, + ); + const body: SubDeptIdListResponse = await res.json(); + if (body.errcode === 0 && body.result?.dept_id_list) { + for (const childId of body.result.dept_id_list) { + queue.push({ id: childId, depth: depth + 1 }); + } + } + } catch (e) { + this.logger.error(`getDeptDepthMap 获取部门 ${id} 子部门失败: ${(e as Error).message}`); + } + } + + return depthMap; + } + // ═══════════════════════════════════════════ // Department detail // ═══════════════════════════════════════════ @@ -492,6 +528,7 @@ export class DingTalkService { // 拉该部门下的用户 const dingUsers = await this.getDeptUsers(token, deptIds[i]); + this.logger.log(`[dingtalk] dept ${deptIds[i]} (${detail.name}): ${dingUsers.length} users`); nodes.push({ id: detail.dept_id,