feat(sync): add ImportClassItemDto and expose deptIds in org-tree-with-users

This commit is contained in:
2026-07-09 12:21:39 +08:00
parent e90f73cb60
commit 166066f49f
2 changed files with 68 additions and 6 deletions

View File

@@ -78,7 +78,12 @@ export interface DingOrgTreeNodeWithUsers {
name: string; name: string;
parentId: number; parentId: number;
children: DingOrgTreeNodeWithUsers[]; children: DingOrgTreeNodeWithUsers[];
users: Array<{ userid: string; name: string; mobile: string }>; users: Array<{
userid: string;
name: string;
mobile: string;
deptIds: number[];
}>;
} }
// ── 考勤排班 API 类型 ── // ── 考勤排班 API 类型 ──
@@ -477,6 +482,9 @@ export class DingTalkService {
// 拉每个部门详情 // 拉每个部门详情
const nodes: DingOrgTreeNodeWithUsers[] = []; const nodes: DingOrgTreeNodeWithUsers[] = [];
// Before dedup: collect deptIds per user
const userDeptMap = new Map<string, number[]>();
for (let i = 0; i < deptIds.length; i++) { for (let i = 0; i < deptIds.length; i++) {
if (i > 0) await this.delay(i); if (i > 0) await this.delay(i);
const detail = await this.getDeptDetail(token, deptIds[i]); const detail = await this.getDeptDetail(token, deptIds[i]);
@@ -494,18 +502,32 @@ export class DingTalkService {
userid: u.userid, userid: u.userid,
name: u.name, name: u.name,
mobile: u.mobile, 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 可能在多个部门出现 // 全局去重:同一个 dingUserId 可能在多个部门出现
const seenUserIds = new Set<string>(); const seenUserIds = new Set<string>();
for (const node of nodes) { for (const node of nodes) {
node.users = node.users.filter((u) => { node.users = node.users
if (seenUserIds.has(u.userid)) return false; .filter((u) => {
seenUserIds.add(u.userid); if (seenUserIds.has(u.userid)) return false;
return true; seenUserIds.add(u.userid);
}); return true;
})
.map((u) => ({
...u,
deptIds: userDeptMap.get(u.userid) || [],
}));
} }
// 组装成树 // 组装成树

View File

@@ -20,9 +20,49 @@ export class ImportUserItemDto {
@IsOptional() @IsOptional()
@IsNumber() @IsNumber()
roleId: number | null; 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 { export class ImportUsersDto {
@IsOptional()
@IsArray()
@ValidateNested({ each: true })
@Type(() => ImportClassItemDto)
classes?: ImportClassItemDto[];
@IsArray() @IsArray()
@ValidateNested({ each: true }) @ValidateNested({ each: true })
@Type(() => ImportUserItemDto) @Type(() => ImportUserItemDto)