feat: 恭学教育基地管理系统初始提交
- 后端: NestJS 11 + TypeORM + JWT认证 + SQLite/MySQL - 前端: React 19 + Ant Design 6 + Vite 8 + ECharts - 功能模块: 数据面板、学生管理、宿舍管理、入住管理、费用录入、账单管理、教室管理、押金管理、操作日志、账号管理 - 支持Docker一键部署
This commit is contained in:
78
backend/src/classrooms/classrooms.service.ts
Normal file
78
backend/src/classrooms/classrooms.service.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository, Not } from 'typeorm';
|
||||
import { Classroom } from '../entities/classroom.entity';
|
||||
import { ClassroomRental } from '../entities/classroom-rental.entity';
|
||||
import { CreateClassroomDto, UpdateClassroomDto } from './dto/classroom.dto';
|
||||
|
||||
@Injectable()
|
||||
export class ClassroomsService {
|
||||
constructor(
|
||||
@InjectRepository(Classroom) private repo: Repository<Classroom>,
|
||||
@InjectRepository(ClassroomRental) private rentalRepo: Repository<ClassroomRental>,
|
||||
) {}
|
||||
|
||||
async findAll(query?: { building?: string; roomType?: string; includeArchived?: boolean }) {
|
||||
const where: any = {};
|
||||
if (query?.building) where.building = query.building;
|
||||
if (query?.roomType) where.roomType = query.roomType;
|
||||
if (!query?.includeArchived) where.status = Not('archived');
|
||||
return this.repo.find({ where, order: { building: 'ASC', name: 'ASC' } });
|
||||
}
|
||||
|
||||
async findOne(id: number) {
|
||||
const cls = await this.repo.findOne({ where: { id } });
|
||||
if (!cls) throw new NotFoundException('教室不存在');
|
||||
return cls;
|
||||
}
|
||||
|
||||
async create(dto: CreateClassroomDto) {
|
||||
const exists = await this.repo.findOne({ where: { name: dto.name } });
|
||||
if (exists) throw new BadRequestException(`教室 ${dto.name} 已存在`);
|
||||
return this.repo.save(this.repo.create(dto));
|
||||
}
|
||||
|
||||
async update(id: number, dto: UpdateClassroomDto) {
|
||||
await this.findOne(id);
|
||||
await this.repo.update(id, dto);
|
||||
return this.repo.findOne({ where: { id } });
|
||||
}
|
||||
|
||||
async remove(id: number) {
|
||||
await this.findOne(id);
|
||||
// 若存在未结束的租赁订单,不允许归档
|
||||
const active = await this.rentalRepo.count({ where: { classroomId: id, status: 'active' } });
|
||||
if (active > 0) throw new BadRequestException('该教室存在进行中的租赁订单,无法归档');
|
||||
await this.repo.update(id, { status: 'archived' });
|
||||
return { message: '已归档' };
|
||||
}
|
||||
|
||||
async restore(id: number) {
|
||||
const cls = await this.findOne(id);
|
||||
if (cls.status !== 'archived') throw new BadRequestException('该教室未被归档');
|
||||
await this.repo.update(id, { status: 'available' });
|
||||
return { message: '已恢复' };
|
||||
}
|
||||
|
||||
async batchImport(rows: { name: string; building?: string; floor?: number; capacity?: number; roomType?: string; courseType?: string; supervisor?: string }[]) {
|
||||
let imported = 0;
|
||||
let skipped = 0;
|
||||
for (const row of rows) {
|
||||
if (!row.name || !row.name.trim()) { skipped++; continue; }
|
||||
const name = row.name.trim();
|
||||
const exists = await this.repo.findOne({ where: { name } });
|
||||
if (exists) { skipped++; continue; }
|
||||
await this.repo.save(this.repo.create({
|
||||
name,
|
||||
building: row.building?.trim() || undefined,
|
||||
floor: row.floor || undefined,
|
||||
capacity: row.capacity || 30,
|
||||
roomType: row.roomType?.trim() || '大',
|
||||
courseType: row.courseType?.trim() || undefined,
|
||||
supervisor: row.supervisor?.trim() || undefined,
|
||||
}));
|
||||
imported++;
|
||||
}
|
||||
return { message: `成功导入 ${imported} 间教室,跳过 ${skipped} 条(重复或空行)`, imported, skipped };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user