From 166066f49f2cc5efce64bafd8fbc5525b2877889 Mon Sep 17 00:00:00 2001 From: wangziqi Date: Thu, 9 Jul 2026 12:21:39 +0800 Subject: [PATCH] feat(sync): add ImportClassItemDto and expose deptIds in org-tree-with-users --- .../src/integration/dingtalk.service.ts | 34 +++++++++++++--- apps/server/src/sync/dto/import-users.dto.ts | 40 +++++++++++++++++++ 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/apps/server/src/integration/dingtalk.service.ts b/apps/server/src/integration/dingtalk.service.ts index 19bf595..224b001 100644 --- a/apps/server/src/integration/dingtalk.service.ts +++ b/apps/server/src/integration/dingtalk.service.ts @@ -78,7 +78,12 @@ export interface DingOrgTreeNodeWithUsers { name: string; parentId: number; children: DingOrgTreeNodeWithUsers[]; - users: Array<{ userid: string; name: string; mobile: string }>; + users: Array<{ + userid: string; + name: string; + mobile: string; + deptIds: number[]; + }>; } // ── 考勤排班 API 类型 ── @@ -477,6 +482,9 @@ export class DingTalkService { // 拉每个部门详情 const nodes: DingOrgTreeNodeWithUsers[] = []; + // Before dedup: collect deptIds per user + const userDeptMap = new Map(); + for (let i = 0; i < deptIds.length; i++) { if (i > 0) await this.delay(i); const detail = await this.getDeptDetail(token, deptIds[i]); @@ -494,18 +502,32 @@ export class DingTalkService { userid: u.userid, name: u.name, mobile: u.mobile, + deptIds: [], })), }); + + // Record which departments each user belongs to + for (const u of dingUsers) { + if (!userDeptMap.has(u.userid)) { + userDeptMap.set(u.userid, []); + } + userDeptMap.get(u.userid)!.push(detail.dept_id); + } } // 全局去重:同一个 dingUserId 可能在多个部门出现 const seenUserIds = new Set(); for (const node of nodes) { - node.users = node.users.filter((u) => { - if (seenUserIds.has(u.userid)) return false; - seenUserIds.add(u.userid); - return true; - }); + node.users = node.users + .filter((u) => { + if (seenUserIds.has(u.userid)) return false; + seenUserIds.add(u.userid); + return true; + }) + .map((u) => ({ + ...u, + deptIds: userDeptMap.get(u.userid) || [], + })); } // 组装成树 diff --git a/apps/server/src/sync/dto/import-users.dto.ts b/apps/server/src/sync/dto/import-users.dto.ts index 1a137cd..7992ad5 100644 --- a/apps/server/src/sync/dto/import-users.dto.ts +++ b/apps/server/src/sync/dto/import-users.dto.ts @@ -20,9 +20,49 @@ export class ImportUserItemDto { @IsOptional() @IsNumber() roleId: number | null; + + @IsArray() + @IsNumber({}, { each: true }) + dingDeptIds: number[]; +} + +export class ImportClassItemDto { + @IsNumber() + deptId: number; + + @IsString() + name: string; + + @IsString() + code: string; + + @IsString() + classType: string; + + @IsOptional() + @IsString() + startDate?: string; + + @IsOptional() + @IsString() + endDate?: string; + + @IsOptional() + @IsNumber() + maxStudents?: number; + + @IsOptional() + @IsString() + notes?: string; } export class ImportUsersDto { + @IsOptional() + @IsArray() + @ValidateNested({ each: true }) + @Type(() => ImportClassItemDto) + classes?: ImportClassItemDto[]; + @IsArray() @ValidateNested({ each: true }) @Type(() => ImportUserItemDto)