# 组织同步 Drawer 只展示最深两层

**日期**：2026-07-09  
**范围**：后端 `DingTalkService.fetchOrgTreeWithUsers` + 前端 `IntegrationConfig` Drawer

## 需求

钉钉组织架构树可能很深（5+ 层），「同步用户」Drawer 中只展示整棵树的最深两层，减少噪音和 API 调用。

- 深度以 rootDeptId=1 的全局树为准
- 最深两层 = depth ∈ [maxDepth-1, maxDepth]
- `fetchOrgTree`（dept picker）不变
- `syncAll` 同步逻辑不变

## 方案

### 后端：`DingTalkService`

#### 新增 `getDeptDepthMap(token)`

```typescript
// BFS 从 rootDeptId=1 出发，返回 Map<deptId, depth(1-based)>
private async getDeptDepthMap(token: string): Promise<Map<number, number>>
```

不调 `getDeptDetail`，仅用 `listsubid` API 遍历树。

#### 修改 `fetchOrgTreeWithUsers(rootDeptId)`

```
depthMap  = getDeptDepthMap(token)           // 全局深度
maxDepth  = max(depthMap.values())
subtree   = getAllDeptIds(token, rootDeptId)  // 子树范围
filtered  = subtree.filter(d => depthMap.get(d) ∈ [maxDepth-1, maxDepth])

for each filtered: getDeptDetail + getDeptUsers
assemble tree（父节点不在 filtered 中的提升为根）
```

#### 边界

|情况|行为|
|---|---|
|树只有 1 层|取 depth=1，展示根部门|
|树 2 层|取 depth=1,2，展示全部（和现在一致）|
|子树最深层 < maxDepth-1|返回空数组|
|中间层有用户|不展示（被裁剪）|

### 前端

零改动。返回数据仍是 `DingOrgTreeNodeWithUsers[]`，只是节点变少。空树时现有 `<Spin />` 兜底。

## 不受影响

- `fetchOrgTree` — dept picker 仍显示完整树
- `syncAll` — 同步全部部门
- `getAllDeptIds` / `getDeptDetail` / `getDeptUsers` — 不变

## 改动量

- `dingtalk.service.ts`：约 30 行（新方法 + 改旧方法）
- 前端：0 行
