feat: implement project development module, transfer management features, and industrial AVM model integration
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { ProjectDevelopmentStatus } from '@prisma/client';
|
||||
import { Type } from 'class-transformer';
|
||||
import {
|
||||
IsString,
|
||||
IsNumber,
|
||||
IsEnum,
|
||||
IsOptional,
|
||||
IsArray,
|
||||
IsObject,
|
||||
Min,
|
||||
Max,
|
||||
MaxLength,
|
||||
IsDateString,
|
||||
} from 'class-validator';
|
||||
|
||||
export class CreateProjectDto {
|
||||
@ApiProperty({ example: 'Vinhomes Grand Park', description: 'Tên dự án' })
|
||||
@IsString()
|
||||
@MaxLength(200)
|
||||
name!: string;
|
||||
|
||||
@ApiProperty({ example: 'vinhomes-grand-park', description: 'URL slug (unique)' })
|
||||
@IsString()
|
||||
@MaxLength(100)
|
||||
slug!: string;
|
||||
|
||||
@ApiProperty({ example: 'Vingroup' })
|
||||
@IsString()
|
||||
developer!: string;
|
||||
|
||||
@ApiPropertyOptional({ example: 'https://example.com/logo.png' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
developerLogo?: string;
|
||||
|
||||
@ApiProperty({ example: 10000, description: 'Tổng số căn hộ/đơn vị' })
|
||||
@IsNumber()
|
||||
@Type(() => Number)
|
||||
@Min(1)
|
||||
totalUnits!: number;
|
||||
|
||||
@ApiProperty({ enum: ProjectDevelopmentStatus, example: 'UNDER_CONSTRUCTION' })
|
||||
@IsEnum(ProjectDevelopmentStatus)
|
||||
status!: ProjectDevelopmentStatus;
|
||||
|
||||
@ApiProperty({ example: 10.8231, description: 'Latitude' })
|
||||
@IsNumber()
|
||||
@Type(() => Number)
|
||||
@Min(-90)
|
||||
@Max(90)
|
||||
latitude!: number;
|
||||
|
||||
@ApiProperty({ example: 106.8368, description: 'Longitude' })
|
||||
@IsNumber()
|
||||
@Type(() => Number)
|
||||
@Min(-180)
|
||||
@Max(180)
|
||||
longitude!: number;
|
||||
|
||||
@ApiProperty({ example: 'Phường Long Thạnh Mỹ, TP. Thủ Đức' })
|
||||
@IsString()
|
||||
address!: string;
|
||||
|
||||
@ApiProperty({ example: 'Long Thạnh Mỹ' })
|
||||
@IsString()
|
||||
ward!: string;
|
||||
|
||||
@ApiProperty({ example: 'Thủ Đức' })
|
||||
@IsString()
|
||||
district!: string;
|
||||
|
||||
@ApiProperty({ example: 'Hồ Chí Minh' })
|
||||
@IsString()
|
||||
city!: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Mô tả dự án' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
description?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Tiện ích dự án (JSON)' })
|
||||
@IsOptional()
|
||||
@IsObject()
|
||||
amenities?: Record<string, unknown>;
|
||||
|
||||
@ApiPropertyOptional({ example: 'https://example.com/masterplan.jpg' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
masterPlanUrl?: string;
|
||||
|
||||
@ApiPropertyOptional({ example: '3000000000', description: 'Giá thấp nhất (VND)' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
minPrice?: string;
|
||||
|
||||
@ApiPropertyOptional({ example: '15000000000', description: 'Giá cao nhất (VND)' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
maxPrice?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Giá/m² range (JSON)' })
|
||||
@IsOptional()
|
||||
@IsObject()
|
||||
pricePerM2Range?: Record<string, unknown>;
|
||||
|
||||
@ApiPropertyOptional({ example: 271, description: 'Tổng diện tích (ha)' })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Type(() => Number)
|
||||
@Min(0)
|
||||
totalArea?: number;
|
||||
|
||||
@ApiPropertyOptional({ example: 14 })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Type(() => Number)
|
||||
buildingCount?: number;
|
||||
|
||||
@ApiPropertyOptional({ example: 35 })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Type(() => Number)
|
||||
floorCount?: number;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Loại căn hộ (JSON)' })
|
||||
@IsOptional()
|
||||
@IsObject()
|
||||
unitTypes?: Record<string, unknown>;
|
||||
|
||||
@ApiPropertyOptional({ example: ['cao-cap', 'can-ho'], description: 'Tags' })
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@IsString({ each: true })
|
||||
tags?: string[];
|
||||
|
||||
@ApiPropertyOptional({ example: '2020-06-01', description: 'Ngày khởi công' })
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
startDate?: string;
|
||||
|
||||
@ApiPropertyOptional({ example: '2025-12-31', description: 'Ngày dự kiến hoàn thành' })
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
completionDate?: string;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { ProjectDevelopmentStatus } from '@prisma/client';
|
||||
import { Type } from 'class-transformer';
|
||||
import { IsString, IsEnum, IsOptional, IsNumber, IsBoolean, Min, Max } from 'class-validator';
|
||||
|
||||
export class SearchProjectsDto {
|
||||
@ApiPropertyOptional({ description: 'Tìm kiếm theo tên, chủ đầu tư, quận, thành phố' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
q?: string;
|
||||
|
||||
@ApiPropertyOptional({ enum: ProjectDevelopmentStatus })
|
||||
@IsOptional()
|
||||
@IsEnum(ProjectDevelopmentStatus)
|
||||
status?: ProjectDevelopmentStatus;
|
||||
|
||||
@ApiPropertyOptional({ example: 'Hồ Chí Minh' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
city?: string;
|
||||
|
||||
@ApiPropertyOptional({ example: 'Thủ Đức' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
district?: string;
|
||||
|
||||
@ApiPropertyOptional({ example: 'Vingroup' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
developer?: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@Type(() => Boolean)
|
||||
isVerified?: boolean;
|
||||
|
||||
@ApiPropertyOptional({ default: 1 })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Type(() => Number)
|
||||
@Min(1)
|
||||
page?: number;
|
||||
|
||||
@ApiPropertyOptional({ default: 20 })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Type(() => Number)
|
||||
@Min(1)
|
||||
@Max(100)
|
||||
limit?: number;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { ProjectDevelopmentStatus } from '@prisma/client';
|
||||
import { Type } from 'class-transformer';
|
||||
import {
|
||||
IsString,
|
||||
IsNumber,
|
||||
IsEnum,
|
||||
IsOptional,
|
||||
IsArray,
|
||||
IsObject,
|
||||
IsBoolean,
|
||||
Min,
|
||||
IsDateString,
|
||||
} from 'class-validator';
|
||||
|
||||
export class UpdateProjectDto {
|
||||
@ApiPropertyOptional() @IsOptional() @IsString() name?: string;
|
||||
@ApiPropertyOptional() @IsOptional() @IsString() developer?: string;
|
||||
@ApiPropertyOptional() @IsOptional() @IsString() developerLogo?: string | null;
|
||||
|
||||
@ApiPropertyOptional() @IsOptional() @IsNumber() @Type(() => Number) @Min(1)
|
||||
totalUnits?: number;
|
||||
|
||||
@ApiPropertyOptional() @IsOptional() @IsNumber() @Type(() => Number) @Min(0)
|
||||
completedUnits?: number;
|
||||
|
||||
@ApiPropertyOptional({ enum: ProjectDevelopmentStatus })
|
||||
@IsOptional() @IsEnum(ProjectDevelopmentStatus)
|
||||
status?: ProjectDevelopmentStatus;
|
||||
|
||||
@ApiPropertyOptional() @IsOptional() @IsString() description?: string | null;
|
||||
@ApiPropertyOptional() @IsOptional() @IsObject() amenities?: Record<string, unknown> | null;
|
||||
@ApiPropertyOptional() @IsOptional() @IsString() masterPlanUrl?: string | null;
|
||||
@ApiPropertyOptional() @IsOptional() @IsString() minPrice?: string | null;
|
||||
@ApiPropertyOptional() @IsOptional() @IsString() maxPrice?: string | null;
|
||||
@ApiPropertyOptional() @IsOptional() @IsObject() pricePerM2Range?: Record<string, unknown> | null;
|
||||
|
||||
@ApiPropertyOptional() @IsOptional() @IsNumber() @Type(() => Number) @Min(0)
|
||||
totalArea?: number | null;
|
||||
|
||||
@ApiPropertyOptional() @IsOptional() @IsNumber() @Type(() => Number) buildingCount?: number | null;
|
||||
@ApiPropertyOptional() @IsOptional() @IsNumber() @Type(() => Number) floorCount?: number | null;
|
||||
@ApiPropertyOptional() @IsOptional() @IsObject() unitTypes?: Record<string, unknown> | null;
|
||||
@ApiPropertyOptional() @IsOptional() @IsArray() media?: Record<string, unknown>[] | null;
|
||||
@ApiPropertyOptional() @IsOptional() @IsArray() documents?: Record<string, unknown>[] | null;
|
||||
@ApiPropertyOptional() @IsOptional() @IsArray() @IsString({ each: true }) tags?: string[];
|
||||
@ApiPropertyOptional() @IsOptional() @IsBoolean() isVerified?: boolean;
|
||||
@ApiPropertyOptional() @IsOptional() @IsDateString() startDate?: string | null;
|
||||
@ApiPropertyOptional() @IsOptional() @IsDateString() completionDate?: string | null;
|
||||
}
|
||||
Reference in New Issue
Block a user