diff --git a/apps/server/src/rooms/rooms.module.ts b/apps/server/src/rooms/rooms.module.ts index 7c18d45..b5959c6 100644 --- a/apps/server/src/rooms/rooms.module.ts +++ b/apps/server/src/rooms/rooms.module.ts @@ -3,13 +3,15 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { Room } from '../entities/room.entity'; import { Occupancy } from '../entities/occupancy.entity'; import { RoomExpense } from '../entities/room-expense.entity'; +import { Bed } from '../entities/bed.entity'; +import { Locker } from '../entities/locker.entity'; import { RoomsService } from './rooms.service'; import { RoomsController } from './rooms.controller'; import { OperationLogsModule } from '../operation-logs/operation-logs.module'; import { CommonModule } from '../common/common.module'; @Module({ - imports: [TypeOrmModule.forFeature([Room, Occupancy, RoomExpense]), OperationLogsModule, CommonModule], + imports: [TypeOrmModule.forFeature([Room, Occupancy, RoomExpense, Bed, Locker]), OperationLogsModule, CommonModule], controllers: [RoomsController], providers: [RoomsService], exports: [RoomsService], diff --git a/apps/server/src/rooms/rooms.service.ts b/apps/server/src/rooms/rooms.service.ts index 7aa40ca..89cce35 100644 --- a/apps/server/src/rooms/rooms.service.ts +++ b/apps/server/src/rooms/rooms.service.ts @@ -5,7 +5,11 @@ 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'; +import { Bed } from '../entities/bed.entity'; +import { Locker } from '../entities/locker.entity'; import { CreateRoomDto, UpdateRoomDto } from './dto/room.dto'; +import { CreateBedDto, UpdateBedDto, BatchCreateBedDto } from './dto/bed.dto'; +import { CreateLockerDto, UpdateLockerDto, BatchCreateLockerDto } from './dto/locker.dto'; @Injectable() export class RoomsService { @@ -13,7 +17,8 @@ export class RoomsService { @InjectRepository(Room) private repo: Repository, @InjectRepository(Occupancy) private occRepo: Repository, @InjectRepository(RoomExpense) private roomExpRepo: Repository, - private readonly scope: CampusScope, + @InjectRepository(Bed) private bedRepo: Repository, + @InjectRepository(Locker) private lockerRepo: Repository, ) {} /** @@ -320,4 +325,122 @@ export class RoomsService { skipped, }; } + + // ── 床位管理 ── + + async getRoomBeds(roomId: number): Promise { + const room = await this.repo.findOne({ where: { id: roomId } }); + if (!room) throw new NotFoundException('宿舍不存在'); + return this.bedRepo.find({ where: { roomId }, order: { bedNumber: 'ASC' } }); + } + + async getRoomAvailableBeds(roomId: number): Promise { + const room = await this.repo.findOne({ where: { id: roomId } }); + if (!room) throw new NotFoundException('宿舍不存在'); + return this.bedRepo.find({ where: { roomId, status: 'available' }, order: { bedNumber: 'ASC' } }); + } + + async createBed(roomId: number, dto: CreateBedDto): Promise { + const room = await this.repo.findOne({ where: { id: roomId } }); + if (!room) throw new NotFoundException('宿舍不存在'); + if (room.status === 'archived') throw new BadRequestException('已归档宿舍不能添加床位'); + const existing = await this.bedRepo.findOne({ where: { roomId, bedNumber: dto.bedNumber } }); + if (existing) throw new BadRequestException('该床位编号已存在'); + const bed = this.bedRepo.create({ ...dto, roomId }); + return this.bedRepo.save(bed); + } + + async updateBed(roomId: number, id: number, dto: UpdateBedDto): Promise { + const bed = await this.bedRepo.findOne({ where: { id, roomId } }); + if (!bed) throw new NotFoundException('床位不存在'); + // 不允许将 occupied 的床位改为 maintenance + if (dto.status === 'maintenance' && bed.status === 'occupied') { + throw new BadRequestException('该床位有人入住,请先退宿'); + } + // 编号唯一性检查 + if (dto.bedNumber && dto.bedNumber !== bed.bedNumber) { + const dup = await this.bedRepo.findOne({ where: { roomId, bedNumber: dto.bedNumber } }); + if (dup) throw new BadRequestException('该床位编号已存在'); + } + Object.assign(bed, dto); + return this.bedRepo.save(bed); + } + + async deleteBed(roomId: number, id: number): Promise { + const bed = await this.bedRepo.findOne({ where: { id, roomId } }); + if (!bed) throw new NotFoundException('床位不存在'); + if (bed.status === 'occupied') throw new BadRequestException('该床位有人入住,无法删除'); + await this.bedRepo.remove(bed); + } + + async batchCreateBeds(roomId: number, dto: BatchCreateBedDto): Promise { + const room = await this.repo.findOne({ where: { id: roomId } }); + if (!room) throw new NotFoundException('宿舍不存在'); + if (room.status === 'archived') throw new BadRequestException('已归档宿舍不能添加床位'); + const existing = await this.bedRepo.count({ where: { roomId } }); + const start = existing + 1; + const beds: Bed[] = []; + for (let i = 0; i < dto.count; i++) { + beds.push(this.bedRepo.create({ roomId, bedNumber: `${start + i}号床` })); + } + return this.bedRepo.save(beds); + } + + // ── 柜子管理 ── + + async getRoomLockers(roomId: number): Promise { + const room = await this.repo.findOne({ where: { id: roomId } }); + if (!room) throw new NotFoundException('宿舍不存在'); + return this.lockerRepo.find({ where: { roomId }, order: { lockerNumber: 'ASC' } }); + } + + async getRoomAvailableLockers(roomId: number): Promise { + const room = await this.repo.findOne({ where: { id: roomId } }); + if (!room) throw new NotFoundException('宿舍不存在'); + return this.lockerRepo.find({ where: { roomId, status: 'available' }, order: { lockerNumber: 'ASC' } }); + } + + async createLocker(roomId: number, dto: CreateLockerDto): Promise { + const room = await this.repo.findOne({ where: { id: roomId } }); + if (!room) throw new NotFoundException('宿舍不存在'); + if (room.status === 'archived') throw new BadRequestException('已归档宿舍不能添加柜子'); + const existing = await this.lockerRepo.findOne({ where: { roomId, lockerNumber: dto.lockerNumber } }); + if (existing) throw new BadRequestException('该柜子编号已存在'); + const locker = this.lockerRepo.create({ ...dto, roomId }); + return this.lockerRepo.save(locker); + } + + async updateLocker(roomId: number, id: number, dto: UpdateLockerDto): Promise { + const locker = await this.lockerRepo.findOne({ where: { id, roomId } }); + if (!locker) throw new NotFoundException('柜子不存在'); + if (dto.status === 'maintenance' && locker.status === 'occupied') { + throw new BadRequestException('该柜子有人占用,请先释放'); + } + if (dto.lockerNumber && dto.lockerNumber !== locker.lockerNumber) { + const dup = await this.lockerRepo.findOne({ where: { roomId, lockerNumber: dto.lockerNumber } }); + if (dup) throw new BadRequestException('该柜子编号已存在'); + } + Object.assign(locker, dto); + return this.lockerRepo.save(locker); + } + + async deleteLocker(roomId: number, id: number): Promise { + const locker = await this.lockerRepo.findOne({ where: { id, roomId } }); + if (!locker) throw new NotFoundException('柜子不存在'); + if (locker.status === 'occupied') throw new BadRequestException('该柜子有人占用,无法删除'); + await this.lockerRepo.remove(locker); + } + + async batchCreateLockers(roomId: number, dto: BatchCreateLockerDto): Promise { + const room = await this.repo.findOne({ where: { id: roomId } }); + if (!room) throw new NotFoundException('宿舍不存在'); + if (room.status === 'archived') throw new BadRequestException('已归档宿舍不能添加柜子'); + const existing = await this.lockerRepo.count({ where: { roomId } }); + const start = existing + 1; + const lockers: Locker[] = []; + for (let i = 0; i < dto.count; i++) { + lockers.push(this.lockerRepo.create({ roomId, lockerNumber: `${start + i}号柜` })); + } + return this.lockerRepo.save(lockers); + } }