diff --git a/apps/admin/src/pages/Occupancies/index.tsx b/apps/admin/src/pages/Occupancies/index.tsx index acb0407..89b3e8b 100644 --- a/apps/admin/src/pages/Occupancies/index.tsx +++ b/apps/admin/src/pages/Occupancies/index.tsx @@ -34,6 +34,7 @@ const OccupanciesPage: React.FC = () => { const [data, setData] = useState([]); const [students, setStudents] = useState([]); const [rooms, setRooms] = useState([]); + const [tenants, setTenants] = useState([]); const [loading, setLoading] = useState(false); const [checkInModal, setCheckInModal] = useState(false); const [checkOutModal, setCheckOutModal] = useState(null); @@ -52,14 +53,16 @@ const OccupanciesPage: React.FC = () => { const fetchData = async () => { setLoading(true); try { - const [occ, stu, rm]: any[] = await Promise.all([ + const [occ, stu, rm, tn]: any[] = await Promise.all([ api.get('/occupancies', { params: { active: showActive ? 'true' : undefined } }), api.get('/students'), api.get('/rooms/overview'), + api.get('/tenants'), ]); setData(occ); setStudents(stu); setRooms(rm); + setTenants(tn); } catch (e) { console.error(e); } @@ -89,6 +92,8 @@ const OccupanciesPage: React.FC = () => { roomId: values.roomId, checkInDate: values.checkInDate.format('YYYY-MM-DD'), billingStartDate: values.billingStartDate?.format('YYYY-MM-DD'), + rentalType: values.rentalType, + tenantId: values.tenantId, notes: values.notes, }); message.success('入住登记成功'); @@ -508,6 +513,28 @@ const OccupanciesPage: React.FC = () => { format="YYYY-MM-DD" /> + + ({ + value: t.id, + label: t.name, + }))} + /> + diff --git a/apps/admin/src/pages/Rooms/index.tsx b/apps/admin/src/pages/Rooms/index.tsx index c36b864..1b77d31 100644 --- a/apps/admin/src/pages/Rooms/index.tsx +++ b/apps/admin/src/pages/Rooms/index.tsx @@ -422,6 +422,19 @@ const RoomsPage: React.FC = () => { placeholder="留空自动解析" /> + + Tenant, { nullable: true }) + @JoinColumn({ name: 'tenant_id' }) + tenant: Tenant; + @CreateDateColumn({ name: 'created_at' }) createdAt: Date; diff --git a/apps/server/src/entities/room.entity.ts b/apps/server/src/entities/room.entity.ts index 4d81bd5..8ab05c6 100644 --- a/apps/server/src/entities/room.entity.ts +++ b/apps/server/src/entities/room.entity.ts @@ -28,6 +28,12 @@ export class Room { @Column({ length: 10, nullable: true }) gender: string; + @Column({ name: 'rental_category', length: 10, default: 'short' }) + rentalCategory: string; + + @Column({ name: 'monthly_rate', type: 'decimal', precision: 10, scale: 2, default: 0 }) + monthlyRate: number; + @CreateDateColumn({ name: 'created_at' }) createdAt: Date; diff --git a/apps/server/src/entities/student.entity.ts b/apps/server/src/entities/student.entity.ts index 7aa4c8b..72b8764 100644 --- a/apps/server/src/entities/student.entity.ts +++ b/apps/server/src/entities/student.entity.ts @@ -4,11 +4,14 @@ import { Column, CreateDateColumn, UpdateDateColumn, + ManyToOne, + JoinColumn, OneToMany, } from 'typeorm'; import { Occupancy } from './occupancy.entity'; import { PersonalExpense } from './personal-expense.entity'; import { Bill } from './bill.entity'; +import { Tenant } from './tenant.entity'; @Entity('students') export class Student { @@ -54,6 +57,13 @@ export class Student { @OneToMany(() => Occupancy, (o) => o.student) occupancies: Occupancy[]; + @Column({ name: 'tenant_id', type: 'integer', nullable: true }) + tenantId: number; + + @ManyToOne(() => Tenant, { nullable: true }) + @JoinColumn({ name: 'tenant_id' }) + tenant: Tenant; + @OneToMany(() => PersonalExpense, (e) => e.student) personalExpenses: PersonalExpense[]; diff --git a/apps/server/src/occupancies/dto/occupancy.dto.ts b/apps/server/src/occupancies/dto/occupancy.dto.ts index 3615c74..d430610 100644 --- a/apps/server/src/occupancies/dto/occupancy.dto.ts +++ b/apps/server/src/occupancies/dto/occupancy.dto.ts @@ -17,6 +17,14 @@ export class CheckInDto { @IsOptional() @IsString() notes?: string; + + @IsOptional() + @IsString() + rentalType?: string; + + @IsOptional() + @IsInt() + tenantId?: number; } export class CheckOutDto { diff --git a/apps/server/src/occupancies/occupancies.service.ts b/apps/server/src/occupancies/occupancies.service.ts index 5e7a74a..dcc8104 100644 --- a/apps/server/src/occupancies/occupancies.service.ts +++ b/apps/server/src/occupancies/occupancies.service.ts @@ -65,6 +65,8 @@ export class OccupanciesService { roomId: dto.roomId, checkInDate: dto.checkInDate, billingStartDate: dto.billingStartDate || dto.checkInDate, + rentalType: dto.rentalType, + tenantId: dto.tenantId, notes: dto.notes, }); const saved = await this.repo.save(occ); diff --git a/apps/server/src/rooms/dto/room.dto.ts b/apps/server/src/rooms/dto/room.dto.ts index 4cb37a9..4dac4dc 100644 --- a/apps/server/src/rooms/dto/room.dto.ts +++ b/apps/server/src/rooms/dto/room.dto.ts @@ -1,4 +1,4 @@ -import { IsString, IsOptional, IsInt, IsEnum, Min } from 'class-validator'; +import { IsString, IsOptional, IsInt, IsEnum, Min, IsNumber } from 'class-validator'; export class CreateRoomDto { @IsString() @@ -19,6 +19,14 @@ export class CreateRoomDto { @IsOptional() @IsString() roomType?: string; + + @IsOptional() + @IsString() + rentalCategory?: string; + + @IsOptional() + @IsNumber() + monthlyRate?: number; } export class UpdateRoomDto { @@ -50,4 +58,12 @@ export class UpdateRoomDto { @IsOptional() @IsEnum(['available', 'full', 'maintenance']) status?: string; + + @IsOptional() + @IsString() + rentalCategory?: string; + + @IsOptional() + @IsNumber() + monthlyRate?: number; }