251210:1709 Frontend: reeactor organization and run build
This commit is contained in:
@@ -19,6 +19,7 @@ import {
|
||||
import { ContractService } from './contract.service.js';
|
||||
import { CreateContractDto } from './dto/create-contract.dto.js';
|
||||
import { UpdateContractDto } from './dto/update-contract.dto.js';
|
||||
import { SearchContractDto } from './dto/search-contract.dto.js';
|
||||
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard.js';
|
||||
import { RequirePermission } from '../../common/decorators/require-permission.decorator.js';
|
||||
|
||||
@@ -38,11 +39,10 @@ export class ContractController {
|
||||
|
||||
@Get()
|
||||
@ApiOperation({
|
||||
summary: 'Get All Contracts (Optional: filter by projectId)',
|
||||
summary: 'Get All Contracts (Search & Filter)',
|
||||
})
|
||||
@ApiQuery({ name: 'projectId', required: false, type: Number })
|
||||
findAll(@Query('projectId') projectId?: number) {
|
||||
return this.contractService.findAll(projectId);
|
||||
findAll(@Query() query: SearchContractDto) {
|
||||
return this.contractService.findAll(query);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
ConflictException,
|
||||
} from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Repository, Like } from 'typeorm';
|
||||
import { Contract } from './entities/contract.entity';
|
||||
import { CreateContractDto } from './dto/create-contract.dto.js';
|
||||
import { UpdateContractDto } from './dto/update-contract.dto.js';
|
||||
@@ -29,17 +29,51 @@ export class ContractService {
|
||||
return this.contractRepo.save(contract);
|
||||
}
|
||||
|
||||
async findAll(projectId?: number) {
|
||||
const query = this.contractRepo
|
||||
.createQueryBuilder('c')
|
||||
.leftJoinAndSelect('c.project', 'p')
|
||||
.orderBy('c.contractCode', 'ASC');
|
||||
async findAll(params?: any) {
|
||||
const { search, projectId, page = 1, limit = 100 } = params || {};
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
if (projectId) {
|
||||
query.where('c.projectId = :projectId', { projectId });
|
||||
const findOptions: any = {
|
||||
relations: ['project'],
|
||||
order: { contractCode: 'ASC' },
|
||||
skip,
|
||||
take: limit,
|
||||
where: [],
|
||||
};
|
||||
|
||||
const searchConditions = [];
|
||||
if (search) {
|
||||
searchConditions.push({ contractCode: Like(`%${search}%`) });
|
||||
searchConditions.push({ contractName: Like(`%${search}%`) });
|
||||
}
|
||||
|
||||
return query.getMany();
|
||||
if (projectId) {
|
||||
// Combine project filter with search if exists
|
||||
if (searchConditions.length > 0) {
|
||||
findOptions.where = searchConditions.map((cond) => ({
|
||||
...cond,
|
||||
projectId,
|
||||
}));
|
||||
} else {
|
||||
findOptions.where = { projectId };
|
||||
}
|
||||
} else {
|
||||
if (searchConditions.length > 0) {
|
||||
findOptions.where = searchConditions;
|
||||
} else {
|
||||
delete findOptions.where; // No filters
|
||||
}
|
||||
}
|
||||
|
||||
const [data, total] = await this.contractRepo.findAndCount(findOptions);
|
||||
|
||||
return {
|
||||
data,
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
totalPages: Math.ceil(total / limit),
|
||||
};
|
||||
}
|
||||
|
||||
async findOne(id: number) {
|
||||
|
||||
@@ -20,6 +20,10 @@ export class CreateOrganizationDto {
|
||||
@Length(1, 255)
|
||||
organizationName!: string;
|
||||
|
||||
@ApiProperty({ example: 1, required: false })
|
||||
@IsOptional()
|
||||
roleId?: number;
|
||||
|
||||
@ApiProperty({ example: true, required: false })
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { IsOptional, IsString, IsInt, Min } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
export class SearchContractDto {
|
||||
@ApiPropertyOptional({ description: 'Search term (code or name)' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
search?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Filter by Project ID' })
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@Type(() => Number)
|
||||
projectId?: number;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Page number', default: 1 })
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
@Type(() => Number)
|
||||
page?: number = 1;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Items per page', default: 100 })
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
@Type(() => Number)
|
||||
limit?: number = 100;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { IsOptional, IsString, IsInt, Min } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
export class SearchOrganizationDto {
|
||||
@ApiPropertyOptional({ description: 'Search term (code or name)' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
search?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Filter by Role ID' })
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@Type(() => Number)
|
||||
roleId?: number;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Page number', default: 1 })
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
@Type(() => Number)
|
||||
page?: number = 1;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Items per page', default: 100 })
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
@Type(() => Number)
|
||||
limit?: number = 100;
|
||||
}
|
||||
@@ -12,6 +12,9 @@ export class Organization extends BaseEntity {
|
||||
@Column({ name: 'organization_name', length: 255 })
|
||||
organizationName!: string;
|
||||
|
||||
@Column({ name: 'role_id', nullable: true })
|
||||
roleId?: number;
|
||||
|
||||
@Column({ name: 'is_active', default: true })
|
||||
isActive!: boolean;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
Patch,
|
||||
Param,
|
||||
Delete,
|
||||
Query,
|
||||
UseGuards,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
@@ -13,6 +14,7 @@ import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { OrganizationService } from './organization.service.js';
|
||||
import { CreateOrganizationDto } from './dto/create-organization.dto.js';
|
||||
import { UpdateOrganizationDto } from './dto/update-organization.dto.js';
|
||||
import { SearchOrganizationDto } from './dto/search-organization.dto.js';
|
||||
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard.js';
|
||||
import { RequirePermission } from '../../common/decorators/require-permission.decorator.js';
|
||||
|
||||
@@ -32,8 +34,8 @@ export class OrganizationController {
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: 'Get All Organizations' })
|
||||
findAll() {
|
||||
return this.orgService.findAll();
|
||||
findAll(@Query() query: SearchOrganizationDto) {
|
||||
return this.orgService.findAll(query);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
ConflictException,
|
||||
} from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Repository, Like } from 'typeorm';
|
||||
import { Organization } from './entities/organization.entity';
|
||||
import { CreateOrganizationDto } from './dto/create-organization.dto.js';
|
||||
import { UpdateOrganizationDto } from './dto/update-organization.dto.js';
|
||||
@@ -29,10 +29,40 @@ export class OrganizationService {
|
||||
return this.orgRepo.save(org);
|
||||
}
|
||||
|
||||
async findAll() {
|
||||
return this.orgRepo.find({
|
||||
async findAll(params?: any) {
|
||||
const { search, page = 1, limit = 100 } = params || {};
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
// Use findAndCount for safer, standard TypeORM queries
|
||||
const findOptions: any = {
|
||||
order: { organizationCode: 'ASC' },
|
||||
});
|
||||
skip,
|
||||
take: limit,
|
||||
};
|
||||
|
||||
if (search) {
|
||||
findOptions.where = [
|
||||
{ organizationCode: Like(`%${search}%`) },
|
||||
{ organizationName: Like(`%${search}%`) },
|
||||
];
|
||||
}
|
||||
|
||||
// Debug logging
|
||||
console.log(
|
||||
'[OrganizationService] Finding all with options:',
|
||||
JSON.stringify(findOptions)
|
||||
);
|
||||
|
||||
const [data, total] = await this.orgRepo.findAndCount(findOptions);
|
||||
console.log(`[OrganizationService] Found ${total} organizations`);
|
||||
|
||||
return {
|
||||
data,
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
totalPages: Math.ceil(total / limit),
|
||||
};
|
||||
}
|
||||
|
||||
async findOne(id: number) {
|
||||
|
||||
@@ -63,7 +63,7 @@ export class ProjectService {
|
||||
);
|
||||
}
|
||||
|
||||
query.orderBy('project.created_at', 'DESC');
|
||||
query.orderBy('project.createdAt', 'DESC');
|
||||
query.skip(skip).take(limit);
|
||||
|
||||
const [items, total] = await query.getManyAndCount();
|
||||
|
||||
Reference in New Issue
Block a user