fix: resolve 9 P0+P1 review findings (bills decorators, campus isolation bypass, ding raw crash, batch import counter, SSE multi-tab, interval leak, dept permissions, cycle prevention, tree depth)

This commit is contained in:
2026-07-06 00:38:51 +08:00
parent 90b6ce4aba
commit b3655da012
8 changed files with 75 additions and 6 deletions

View File

@@ -22,12 +22,33 @@ export class DepartmentsService {
}
async findTree(): Promise<Department[]> {
// Load ALL departments flat (no relations — avoids N+1 and only loads 1 level),
// then build the full tree in memory.
const all = await this.deptRepo.find({
where: { status: 'active' },
order: { sortOrder: 'ASC', name: 'ASC' },
relations: ['children'],
});
return all.filter((d) => d.parentId === null);
const byParent = new Map<number | null, Department[]>();
for (const dept of all) {
const key = dept.parentId ?? null;
const list = byParent.get(key);
if (list) {
list.push(dept);
} else {
byParent.set(key, [dept]);
}
}
const attachChildren = (dept: Department): void => {
const children = byParent.get(dept.id) ?? [];
dept.children = children;
for (const child of children) attachChildren(child);
};
const roots = byParent.get(null) ?? [];
for (const root of roots) attachChildren(root);
return roots;
}
async findOne(id: number): Promise<Department> {
@@ -43,6 +64,19 @@ export class DepartmentsService {
async update(id: number, dto: UpdateDepartmentDto): Promise<Department> {
const dept = await this.findOne(id);
// Prevent parent cycles: parentId must not be the dept itself or one of its descendants
if (dto.parentId !== undefined && dto.parentId !== null) {
const newParentId = dto.parentId;
if (newParentId === id) {
throw new ConflictException('不能将部门的上级设为自身');
}
const descendantIds = await this.getDescendantIds(id);
if (descendantIds.includes(newParentId)) {
throw new ConflictException('不能将部门的上级设为其子部门,会形成循环');
}
}
Object.assign(dept, dto);
return this.deptRepo.save(dept);
}