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;
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<string, number[]>();
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<string>();
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) || [],
}));
}
// 组装成树

View File

@@ -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)