690402:2046 fix correspondence ATG Gemini Flash
CI / CD Pipeline / build (push) Successful in 7m10s
CI / CD Pipeline / deploy (push) Failing after 10m1s

This commit is contained in:
2026-04-02 20:46:56 +07:00
parent 92a9b6898b
commit c188219e28
6 changed files with 98 additions and 20 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ services:
# ใช้ Command นี้เพื่อตั้ง Password # ใช้ Command นี้เพื่อตั้ง Password
command: redis-server --requirepass "Center2025" command: redis-server --requirepass "Center2025"
ports: ports:
- '6379:6379' - '16379:6379'
volumes: volumes:
- redis_data:/data - redis_data:/data
networks: networks:
@@ -130,24 +130,34 @@ export class DashboardService {
.createQueryBuilder('log') .createQueryBuilder('log')
.leftJoin('log.user', 'user') .leftJoin('log.user', 'user')
.select([ .select([
'log.auditId',
'log.action', 'log.action',
'log.entityType', 'log.entityType',
'log.entityId', 'log.entityId',
'log.detailsJson', 'log.detailsJson',
'log.createdAt', 'log.createdAt',
'user.username', 'user.username',
'user.firstName',
'user.lastName',
]) ])
.orderBy('log.createdAt', 'DESC') .orderBy('log.createdAt', 'DESC')
.limit(limit) .limit(limit)
.getMany(); .getMany();
return logs.map((log) => ({ return logs.map((log) => ({
id: log.auditId,
action: log.action, action: log.action,
entityType: log.entityType, entityType: log.entityType,
entityId: log.entityId, entityId: log.entityId,
details: log.detailsJson, details: log.detailsJson,
createdAt: log.createdAt, createdAt: log.createdAt,
username: log.user?.username, user: log.user
? {
username: log.user.username,
firstName: log.user.firstName,
lastName: log.user.lastName,
}
: undefined,
})); }));
} }
@@ -22,6 +22,9 @@ export class GetActivityDto {
* DTO สำหรับ Response ของ Activity Item * DTO สำหรับ Response ของ Activity Item
*/ */
export class ActivityItemDto { export class ActivityItemDto {
@ApiPropertyOptional({ description: 'ID ของ Activity' })
id!: string;
@ApiPropertyOptional({ description: 'Action ที่กระทำ' }) @ApiPropertyOptional({ description: 'Action ที่กระทำ' })
action!: string; action!: string;
@@ -37,6 +40,10 @@ export class ActivityItemDto {
@ApiPropertyOptional({ description: 'วันที่กระทำ' }) @ApiPropertyOptional({ description: 'วันที่กระทำ' })
createdAt!: Date; createdAt!: Date;
@ApiPropertyOptional({ description: 'ชื่อผู้ใช้' }) @ApiPropertyOptional({ description: 'ข้อมูลผู้ใช้' })
username?: string; user?: {
username: string;
firstName?: string;
lastName?: string;
};
} }
@@ -53,7 +53,7 @@ export function PendingTasks({ tasks, isLoading }: PendingTasksProps) {
) : ( ) : (
tasks.map((task) => ( tasks.map((task) => (
<Link <Link
key={task.id} key={task.publicId}
href={task.url} href={task.url}
className="block p-3 bg-muted/40 rounded-lg border hover:bg-muted/60 transition-colors group" className="block p-3 bg-muted/40 rounded-lg border hover:bg-muted/60 transition-colors group"
> >
+59 -10
View File
@@ -1,6 +1,31 @@
import apiClient from '@/lib/api/client'; import apiClient from '@/lib/api/client';
import { DashboardStats, ActivityLog, PendingTask } from '@/types/dashboard'; import { DashboardStats, ActivityLog, PendingTask } from '@/types/dashboard';
interface RawActivityLog {
id: string;
action: string;
entityType?: string;
entityId?: string;
details?: Record<string, unknown>;
createdAt: string;
user?: {
username: string;
firstName?: string;
lastName?: string;
};
}
interface RawPendingTask {
instanceId: string;
workflowCode: string;
currentState: string;
entityType: string;
entityId: string;
documentNumber: string;
subject: string;
assignedAt: string;
}
export const dashboardService = { export const dashboardService = {
getStats: async (): Promise<DashboardStats> => { getStats: async (): Promise<DashboardStats> => {
const response = await apiClient.get('/dashboard/stats'); const response = await apiClient.get('/dashboard/stats');
@@ -10,9 +35,23 @@ export const dashboardService = {
getRecentActivity: async (): Promise<ActivityLog[]> => { getRecentActivity: async (): Promise<ActivityLog[]> => {
try { try {
const response = await apiClient.get('/dashboard/activity'); const response = await apiClient.get('/dashboard/activity');
// ตรวจสอบว่า response.data เป็น array จริงๆ
if (Array.isArray(response.data)) { if (Array.isArray(response.data)) {
return response.data; return (response.data as RawActivityLog[]).map((log) => {
const firstName = log.user?.firstName || '';
const lastName = log.user?.lastName || '';
const fullName = firstName || lastName ? `${firstName} ${lastName}`.trim() : log.user?.username || 'System';
const initials = firstName && lastName ? `${firstName[0]}${lastName[0]}` : (log.user?.username?.[0] || 'S').toUpperCase();
return {
...log,
user: {
name: fullName,
initials: initials,
},
description: (log.details?.description as string) || `${log.action} ${log.entityType || ''} ${log.entityId || ''}`,
targetUrl: `/${(log.entityType || 'correspondence').toLowerCase()}s/${log.entityId || ''}`,
} as ActivityLog;
});
} }
return []; return [];
} catch (_error) { } catch (_error) {
@@ -23,14 +62,24 @@ export const dashboardService = {
getPendingTasks: async (): Promise<PendingTask[]> => { getPendingTasks: async (): Promise<PendingTask[]> => {
try { try {
const response = await apiClient.get('/dashboard/pending'); const response = await apiClient.get('/dashboard/pending');
// Backend คืน { data: [], meta: {} } ต้องดึง data ออกมา const rawTasks = (response.data?.data || (Array.isArray(response.data) ? response.data : [])) as RawPendingTask[];
if (response.data?.data && Array.isArray(response.data.data)) {
return response.data.data; return rawTasks.map((task) => {
} const assignedAt = new Date(task.assignedAt);
if (Array.isArray(response.data)) { const now = new Date();
return response.data; const diffTime = now.getTime() - assignedAt.getTime();
} const daysOverdue = Math.max(0, Math.floor(diffTime / (1000 * 60 * 60 * 24)));
return [];
return {
...task,
publicId: task.instanceId,
title: task.subject || task.documentNumber,
description: task.currentState || task.workflowCode,
daysOverdue,
url: `/${(task.entityType || 'correspondence').toLowerCase()}s/${task.entityId}`,
priority: daysOverdue > 2 ? 'HIGH' : 'MEDIUM',
};
});
} catch (_error) { } catch (_error) {
return []; return [];
} }
+17 -5
View File
@@ -8,20 +8,32 @@ export interface DashboardStats {
} }
export interface ActivityLog { export interface ActivityLog {
id: number; id: string;
action: string;
entityType?: string;
entityId?: string;
details?: Record<string, unknown>;
createdAt: string;
username?: string;
user: { user: {
name: string; name: string;
initials: string; initials: string;
avatar?: string; avatar?: string;
}; };
action: string;
description: string;
createdAt: string;
targetUrl: string; targetUrl: string;
description: string;
} }
export interface PendingTask { export interface PendingTask {
id: number; publicId: string;
workflowCode: string;
currentState: string;
entityType: string;
entityId: string;
documentNumber: string;
subject: string;
assignedAt: string;
// Derived fields for UI
title: string; title: string;
description: string; description: string;
daysOverdue: number; daysOverdue: number;