251211:1622 Frontend: refactor Dashboard (not finish)
Some checks failed
Spec Validation / validate-markdown (push) Has been cancelled
Spec Validation / validate-diagrams (push) Has been cancelled
Spec Validation / check-todos (push) Has been cancelled

This commit is contained in:
admin
2025-12-11 16:22:50 +07:00
parent 3fa28bd14f
commit 2473c4c474
32 changed files with 1115 additions and 260 deletions

View File

@@ -207,15 +207,34 @@ export class CorrespondenceService {
}
async findAll(searchDto: SearchCorrespondenceDto = {}) {
const { search, typeId, projectId, statusId } = searchDto;
const {
search,
typeId,
projectId,
statusId,
page = 1,
limit = 10,
} = searchDto;
const skip = (page - 1) * limit;
const query = this.correspondenceRepo
.createQueryBuilder('corr')
.leftJoinAndSelect('corr.revisions', 'rev')
// Change: Query from Revision Repo
const query = this.revisionRepo
.createQueryBuilder('rev')
.leftJoinAndSelect('rev.correspondence', 'corr')
.leftJoinAndSelect('corr.type', 'type')
.leftJoinAndSelect('corr.project', 'project')
.leftJoinAndSelect('corr.originator', 'org')
.where('rev.isCurrent = :isCurrent', { isCurrent: true });
.leftJoinAndSelect('rev.status', 'status');
// Filter by Revision Status
const revStatus = searchDto.revisionStatus || 'CURRENT';
if (revStatus === 'CURRENT') {
query.where('rev.isCurrent = :isCurrent', { isCurrent: true });
} else if (revStatus === 'OLD') {
query.where('rev.isCurrent = :isCurrent', { isCurrent: false });
}
// If 'ALL', no filter needed on isCurrent
if (projectId) {
query.andWhere('corr.projectId = :projectId', { projectId });
@@ -236,9 +255,20 @@ export class CorrespondenceService {
);
}
query.orderBy('corr.createdAt', 'DESC');
// Default Sort: Latest Created
query.orderBy('rev.createdAt', 'DESC').skip(skip).take(limit);
return query.getMany();
const [items, total] = await query.getManyAndCount();
return {
data: items,
meta: {
total,
page,
limit,
totalPages: Math.ceil(total / limit),
},
};
}
async findOne(id: number) {

View File

@@ -28,6 +28,13 @@ export class SearchCorrespondenceDto {
@IsInt()
statusId?: number;
@ApiPropertyOptional({
description: 'Revision Filter: CURRENT (default), ALL, OLD',
})
@IsOptional()
@IsString()
revisionStatus?: 'CURRENT' | 'ALL' | 'OLD';
@ApiPropertyOptional({ description: 'Page number (default 1)', default: 1 })
@IsOptional()
@Type(() => Number)

View File

@@ -80,10 +80,31 @@ export class DashboardService {
10
);
// นับเอกสารที่อนุมัติแล้ว (APPROVED)
// NOTE: อาจจะต้องปรับ logic ตาม Business ว่า "อนุมัติ" หมายถึงอะไร
// เบื้องต้นนับจาก CorrespondenceStatus ที่เป็น 'APPROVED' หรือ 'CODE 1'
// หรือนับจาก Workflow ที่ Completed และ Action เป็น APPROVE
// เพื่อความง่ายในเบื้องต้น นับจาก CorrespondenceRevision ที่มี status 'APPROVED' (ถ้ามี)
// หรือนับจาก RFA ที่มี Approve Code
// สำหรับ LCBP3 นับ RFA ที่ approveCodeId ไม่ใช่ null (หรือ check status code = APR/FAP)
// และ Correspondence ทั่วไปที่มีสถานะ Completed
// เพื่อความรวดเร็ว ใช้วิธีนับ Revision ที่ isCurrent = 1 และ statusCode = 'APR' (Approved)
// Check status code 'APR' exists
const aprStatusCount = await this.dataSource.query(`
SELECT COUNT(r.id) as count
FROM correspondence_revisions r
JOIN correspondence_status s ON r.correspondence_status_id = s.id
WHERE r.is_current = 1 AND s.status_code IN ('APR', 'CMP')
`);
const approved = parseInt(aprStatusCount[0]?.count || '0', 10);
return {
totalDocuments,
documentsThisMonth,
pendingApprovals,
approved,
totalRfas,
totalCirculations,
};

View File

@@ -16,6 +16,9 @@ export class DashboardStatsDto {
@ApiProperty({ description: 'จำนวนงานที่รออนุมัติ', example: 12 })
pendingApprovals!: number;
@ApiProperty({ description: 'จำนวนเอกสารที่อนุมัติแล้ว', example: 100 })
approved!: number;
@ApiProperty({ description: 'จำนวน RFA ทั้งหมด', example: 45 })
totalRfas!: number;

View File

@@ -174,7 +174,7 @@ export class RfaService {
const rfaItems = shopDrawings.map((sd) =>
queryRunner.manager.create(RfaItem, {
rfaRevisionId: savedCorr.id, // Use Correspondence ID as per schema
rfaRevisionId: savedRevision.id, // Correctly link to RfaRevision
shopDrawingRevisionId: sd.id,
})
);
@@ -244,8 +244,22 @@ export class RfaService {
.createQueryBuilder('rfa')
.leftJoinAndSelect('rfa.revisions', 'rev')
.leftJoinAndSelect('rev.correspondence', 'corr')
.leftJoinAndSelect('corr.project', 'project')
.leftJoinAndSelect('rfa.discipline', 'discipline')
.leftJoinAndSelect('rev.statusCode', 'status')
.where('rev.isCurrent = :isCurrent', { isCurrent: true });
.leftJoinAndSelect('rev.items', 'items')
.leftJoinAndSelect('items.shopDrawingRevision', 'sdRev')
.leftJoinAndSelect('sdRev.attachments', 'attachments');
// Filter by Revision Status (from query param 'revisionStatus')
const revStatus = query.revisionStatus || 'CURRENT';
if (revStatus === 'CURRENT') {
queryBuilder.where('rev.isCurrent = :isCurrent', { isCurrent: true });
} else if (revStatus === 'OLD') {
queryBuilder.where('rev.isCurrent = :isCurrent', { isCurrent: false });
}
// If 'ALL', no filter
if (projectId) {
queryBuilder.andWhere('corr.projectId = :projectId', { projectId });
@@ -268,6 +282,10 @@ export class RfaService {
.take(limit)
.getManyAndCount();
this.logger.log(
`[DEBUG] RFA findAll: Found ${total} items. Query: ${JSON.stringify(query)}`
);
return {
data: items,
meta: {