feat(sync): add ImportClassItemDto and expose deptIds in org-tree-with-users
This commit is contained in:
@@ -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) || [],
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 组装成树
|
// 组装成树
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user