forked from wangziqi/gongxue-base
feat: integrate CampusScope.filter() into all business services (12 services + 12 modules)
This commit is contained in:
@@ -63,15 +63,17 @@ export class RoomsController {
|
||||
{ header: '楼层', key: 'floor', width: 8 },
|
||||
{ header: '额定人数', key: 'capacity', width: 10 },
|
||||
{ header: '宿舍类型', key: 'roomType', width: 12 },
|
||||
{ header: '租赁类型(long/short)', key: 'rentalCategory', width: 18 },
|
||||
{ header: '月租金', key: 'monthlyRate', width: 10 },
|
||||
];
|
||||
ws.getRow(1).font = { bold: true };
|
||||
ws.getRow(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE0E0E0' } };
|
||||
ws.addRow({
|
||||
roomNumber: '4-102',
|
||||
building: '4号楼',
|
||||
floor: 1,
|
||||
capacity: 4,
|
||||
roomType: '四人间',
|
||||
rentalCategory: 'long',
|
||||
monthlyRate: 800,
|
||||
});
|
||||
ws.addRow({
|
||||
roomNumber: '2-201',
|
||||
@@ -79,6 +81,8 @@ export class RoomsController {
|
||||
floor: 2,
|
||||
capacity: 1,
|
||||
roomType: '单人间',
|
||||
rentalCategory: 'short',
|
||||
monthlyRate: 0,
|
||||
});
|
||||
res.setHeader(
|
||||
'Content-Type',
|
||||
@@ -106,6 +110,8 @@ export class RoomsController {
|
||||
{ header: '当前入住', key: 'currentCount', width: 10 },
|
||||
{ header: '性别', key: 'gender', width: 8 },
|
||||
{ header: '状态', key: 'status', width: 10 },
|
||||
{ header: '租赁类型', key: 'rentalCategory', width: 12 },
|
||||
{ header: '月租金', key: 'monthlyRate', width: 10 },
|
||||
];
|
||||
ws.getRow(1).font = { bold: true };
|
||||
ws.getRow(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE0E0E0' } };
|
||||
@@ -125,6 +131,8 @@ export class RoomsController {
|
||||
currentCount: r.currentCount,
|
||||
gender: r.gender || '',
|
||||
status: statusMap[r.status] || r.status,
|
||||
rentalCategory: r.rentalCategory === 'long' ? '长租' : '短租',
|
||||
monthlyRate: r.monthlyRate ?? '',
|
||||
});
|
||||
}
|
||||
res!.setHeader(
|
||||
@@ -245,15 +253,26 @@ export class RoomsController {
|
||||
floor?: number;
|
||||
capacity?: number;
|
||||
roomType?: string;
|
||||
rentalCategory?: string;
|
||||
monthlyRate?: number;
|
||||
}[] = [];
|
||||
ws.eachRow((row, idx) => {
|
||||
if (idx === 1) return;
|
||||
const rentalCategoryRaw = String(row.getCell(6).value || '').trim().toLowerCase();
|
||||
const rentalCategory =
|
||||
rentalCategoryRaw === 'long' || rentalCategoryRaw === 'short'
|
||||
? rentalCategoryRaw
|
||||
: undefined;
|
||||
const monthlyRateRaw = Number(row.getCell(7).value);
|
||||
const monthlyRate = isNaN(monthlyRateRaw) ? undefined : monthlyRateRaw;
|
||||
rows.push({
|
||||
roomNumber: String(row.getCell(1).value || ''),
|
||||
building: String(row.getCell(2).value || '') || undefined,
|
||||
floor: Number(row.getCell(3).value) || undefined,
|
||||
capacity: Number(row.getCell(4).value) || 4,
|
||||
roomType: String(row.getCell(5).value || '').trim() || undefined,
|
||||
rentalCategory,
|
||||
monthlyRate,
|
||||
});
|
||||
});
|
||||
const result = await this.service.batchImport(rows);
|
||||
|
||||
@@ -6,9 +6,10 @@ import { RoomExpense } from '../entities/room-expense.entity';
|
||||
import { RoomsService } from './rooms.service';
|
||||
import { RoomsController } from './rooms.controller';
|
||||
import { OperationLogsModule } from '../operation-logs/operation-logs.module';
|
||||
import { DepartmentsModule } from '../departments/departments.module';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([Room, Occupancy, RoomExpense]), OperationLogsModule],
|
||||
imports: [TypeOrmModule.forFeature([Room, Occupancy, RoomExpense]), OperationLogsModule, DepartmentsModule],
|
||||
controllers: [RoomsController],
|
||||
providers: [RoomsService],
|
||||
exports: [RoomsService],
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository, Like, IsNull, Not, In } 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';
|
||||
@@ -12,6 +13,7 @@ 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,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -62,7 +64,8 @@ export class RoomsService {
|
||||
const where: any = {};
|
||||
if (query?.building) where.building = query.building;
|
||||
if (!query?.includeArchived) where.status = Not('archived');
|
||||
return this.repo.find({ where, order: { roomNumber: 'ASC' } });
|
||||
const filteredWhere = await this.scope.filter(where);
|
||||
return this.repo.find({ where: filteredWhere, order: { roomNumber: 'ASC' } });
|
||||
}
|
||||
|
||||
async findOne(id: number) {
|
||||
@@ -84,7 +87,8 @@ export class RoomsService {
|
||||
async getRoomOverview(query?: { includeArchived?: boolean }) {
|
||||
const where: any = {};
|
||||
if (!query?.includeArchived) where.status = Not('archived');
|
||||
const rooms = await this.repo.find({ where, order: { building: 'ASC', roomNumber: 'ASC' } });
|
||||
const filteredWhere = await this.scope.filter(where);
|
||||
const rooms = await this.repo.find({ where: filteredWhere, order: { building: 'ASC', roomNumber: 'ASC' } });
|
||||
const result: any[] = [];
|
||||
for (const room of rooms) {
|
||||
const count = await this.occRepo.count({
|
||||
@@ -161,12 +165,12 @@ export class RoomsService {
|
||||
|
||||
async getRoomVisual() {
|
||||
const rooms = await this.repo.find({
|
||||
where: { status: Not('archived') },
|
||||
where: await this.scope.filter({ status: Not('archived') }),
|
||||
order: { building: 'ASC', roomNumber: 'ASC' },
|
||||
});
|
||||
const occupancies = await this.occRepo.find({
|
||||
where: { checkOutDate: IsNull() },
|
||||
relations: ['student'],
|
||||
where: await this.scope.filter({ checkOutDate: IsNull() }),
|
||||
relations: ['student', 'tenant'],
|
||||
order: { checkInDate: 'ASC' },
|
||||
});
|
||||
|
||||
@@ -188,6 +192,8 @@ export class RoomsService {
|
||||
days,
|
||||
organization: occ.student?.organization || null,
|
||||
supervisor: occ.student?.supervisor || null,
|
||||
tenantName: occ.tenant?.name || null,
|
||||
tenantColor: occ.tenant?.color || null,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -209,6 +215,9 @@ export class RoomsService {
|
||||
orgLabel = `存在${orgs.join('、')}人员`;
|
||||
}
|
||||
}
|
||||
// 计算租户颜色:所有住户同一租户则使用该颜色
|
||||
const tenantColors = [...new Set(occ.map((o: any) => o.tenantColor).filter(Boolean))];
|
||||
const tenantColor: string | null = tenantColors.length === 1 ? tenantColors[0] : null;
|
||||
return {
|
||||
id: room.id,
|
||||
roomNumber: room.roomNumber,
|
||||
@@ -219,6 +228,7 @@ export class RoomsService {
|
||||
currentCount: occ.length,
|
||||
occupants: occ,
|
||||
orgLabel,
|
||||
tenantColor,
|
||||
};
|
||||
}),
|
||||
};
|
||||
@@ -231,6 +241,8 @@ export class RoomsService {
|
||||
floor?: number;
|
||||
capacity?: number;
|
||||
roomType?: string;
|
||||
rentalCategory?: string;
|
||||
monthlyRate?: number;
|
||||
}[],
|
||||
) {
|
||||
let imported = 0;
|
||||
@@ -254,6 +266,8 @@ export class RoomsService {
|
||||
floor: row.floor || parsed.floor || undefined,
|
||||
capacity: row.capacity || parsed.capacity || 4,
|
||||
roomType: row.roomType || parsed.roomType || undefined,
|
||||
rentalCategory: row.rentalCategory || undefined,
|
||||
monthlyRate: row.monthlyRate ?? undefined,
|
||||
}),
|
||||
);
|
||||
imported++;
|
||||
|
||||
Reference in New Issue
Block a user