refactor(server): remove Department/UserDepartment entities, CampusScope, and departmentId from all entities

- Delete department.entity.ts, user-department.entity.ts
- Remove Department/UserDepartment from entities/index.ts
- Remove departmentId column from 18 entities (AttendanceRecord, ArchiveAttachment, Bill, ClassSchedule, Classroom, ClassroomRental, Deposit, DepositInstallment, ExamScore, LearningRecord, Occupancy, PersonalExpense, ResultArchive, Room, RoomExpense, Student, StudentEnrollment, StudentProfile, StudentReport)
- Remove departments/ module entirely
- Delete campus-scope.ts, campus-scope.middleware.ts (request-utils.ts kept — it's just IP extraction)
- Simplify common.module.ts to empty module
- Remove CampusScopeMiddleware from app.module.ts
- Remove all CampusScope injections and filter calls across all services
- Remove departmentId from all DTOs and controllers
- Simplify dingtalk/wecom sync to only sync users (no dept table)
- Update seed module to remove department seeding
- Clean frontend compilation
This commit is contained in:
2026-07-09 17:51:32 +08:00
parent b0f7883f33
commit 6029d8e2fd
68 changed files with 220 additions and 1516 deletions

View File

@@ -28,9 +28,6 @@ export class CreateRoomDto {
@IsNumber()
monthlyRate?: number;
@IsOptional()
@IsInt()
departmentId?: number;
}
export class UpdateRoomDto {

View File

@@ -360,8 +360,7 @@ export class RoomsController {
monthlyRate,
});
});
const departmentId = req.headers?.['x-campus-id'] ? parseInt(String(req.headers['x-campus-id']), 10) || undefined : undefined;
const result = await this.service.batchImport(rows, departmentId);
const result = await this.service.batchImport(rows);
await this.logService.log({
userId: req.user?.id,
username: req.user?.username,

View File

@@ -1,7 +1,7 @@
import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, Like, IsNull, Not, In, LessThanOrEqual, MoreThanOrEqual } from 'typeorm';
import { CampusScope } from '../common/campus-scope';
import { Room } from '../entities/room.entity';
import { Occupancy } from '../entities/occupancy.entity';
import { RoomExpense } from '../entities/room-expense.entity';
@@ -17,7 +17,6 @@ export class RoomsService {
@InjectRepository(Room) private repo: Repository<Room>,
@InjectRepository(Occupancy) private occRepo: Repository<Occupancy>,
@InjectRepository(RoomExpense) private roomExpRepo: Repository<RoomExpense>,
private readonly scope: CampusScope,
@InjectRepository(Bed) private bedRepo: Repository<Bed>,
@InjectRepository(Locker) private lockerRepo: Repository<Locker>,
) {}
@@ -69,8 +68,7 @@ export class RoomsService {
const where: any = {};
if (query?.building) where.building = query.building;
if (!query?.includeArchived) where.status = Not('archived');
const filteredWhere = await this.scope.filter(where);
return this.repo.find({ where: filteredWhere, order: { roomNumber: 'ASC' } });
return this.repo.find({ where, order: { roomNumber: 'ASC' } });
}
async findOne(id: number) {
@@ -92,8 +90,7 @@ export class RoomsService {
async getRoomOverview(query?: { includeArchived?: boolean }) {
const where: any = {};
if (!query?.includeArchived) where.status = Not('archived');
const filteredWhere = await this.scope.filter(where);
const rooms = await this.repo.find({ where: filteredWhere, order: { building: 'ASC', roomNumber: 'ASC' } });
const rooms = await this.repo.find({ where, order: { building: 'ASC', roomNumber: 'ASC' } });
const result: any[] = [];
for (const room of rooms) {
const count = await this.occRepo.count({
@@ -113,7 +110,6 @@ export class RoomsService {
roomType: dto.roomType ?? parsed.roomType,
capacity: dto.capacity ?? parsed.capacity,
});
if (dto.departmentId) entity.departmentId = dto.departmentId;
return this.repo.save(entity);
}
@@ -184,20 +180,17 @@ export class RoomsService {
// 实时视图排除已归档房间;历史视图不排除——当时有人住的房间即使现在已归档也应显示。
const rooms = await this.repo.find({
where: await this.scope.filter(isHistorical ? {} : { status: Not('archived') }),
where: isHistorical ? {} : { status: Not('archived') },
order: { building: 'ASC', roomNumber: 'ASC' },
});
// scope.filter() produces identical scope conditions within the same request;
// extract once and spread to avoid redundant calls.
const scopeWhere = await this.scope.filter({});
const occupancies = await this.occRepo.find({
where: isHistorical
? [
{ ...scopeWhere, checkInDate: LessThanOrEqual(targetDate), checkOutDate: IsNull() },
{ ...scopeWhere, checkInDate: LessThanOrEqual(targetDate), checkOutDate: MoreThanOrEqual(targetDate) },
{ checkInDate: LessThanOrEqual(targetDate), checkOutDate: IsNull() },
{ checkInDate: LessThanOrEqual(targetDate), checkOutDate: MoreThanOrEqual(targetDate) },
]
: { ...scopeWhere, checkOutDate: IsNull() },
: { checkOutDate: IsNull() },
relations: ['student', 'tenant'],
order: { checkInDate: 'ASC' },
});
@@ -297,7 +290,6 @@ export class RoomsService {
rentalCategory?: string;
monthlyRate?: number;
}[],
departmentId?: number,
) {
let imported = 0;
let skipped = 0;
@@ -322,7 +314,6 @@ export class RoomsService {
roomType: row.roomType || parsed.roomType || undefined,
rentalCategory: row.rentalCategory || undefined,
monthlyRate: row.monthlyRate ?? undefined,
departmentId: departmentId ?? undefined,
}),
);
imported++;