251208:0010 Backend & Frontend Debug
This commit is contained in:
20
frontend/lib/services/audit-log.service.ts
Normal file
20
frontend/lib/services/audit-log.service.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import apiClient from "@/lib/api/client";
|
||||
|
||||
export interface AuditLogRaw {
|
||||
audit_log_id: number;
|
||||
user_id: number;
|
||||
user_name?: string;
|
||||
action: string;
|
||||
entity_type: string;
|
||||
entity_id: string; // or number
|
||||
description: string;
|
||||
ip_address?: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export const auditLogService = {
|
||||
getLogs: async (params?: any) => {
|
||||
const response = await apiClient.get<AuditLogRaw[]>("/audit-logs", { params });
|
||||
return response.data;
|
||||
}
|
||||
};
|
||||
@@ -1,9 +1,9 @@
|
||||
// File: lib/services/contract-drawing.service.ts
|
||||
import apiClient from "@/lib/api/client";
|
||||
import {
|
||||
CreateContractDrawingDto,
|
||||
UpdateContractDrawingDto,
|
||||
SearchContractDrawingDto
|
||||
import {
|
||||
CreateContractDrawingDto,
|
||||
UpdateContractDrawingDto,
|
||||
SearchContractDrawingDto
|
||||
} from "@/types/dto/drawing/contract-drawing.dto";
|
||||
|
||||
export const contractDrawingService = {
|
||||
@@ -11,8 +11,8 @@ export const contractDrawingService = {
|
||||
* ดึงรายการแบบสัญญา (Contract Drawings)
|
||||
*/
|
||||
getAll: async (params: SearchContractDrawingDto) => {
|
||||
// GET /contract-drawings?projectId=1&page=1...
|
||||
const response = await apiClient.get("/contract-drawings", { params });
|
||||
// GET /drawings/contract?projectId=1&page=1...
|
||||
const response = await apiClient.get("/drawings/contract", { params });
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -20,7 +20,7 @@ export const contractDrawingService = {
|
||||
* ดึงรายละเอียดตาม ID
|
||||
*/
|
||||
getById: async (id: string | number) => {
|
||||
const response = await apiClient.get(`/contract-drawings/${id}`);
|
||||
const response = await apiClient.get(`/drawings/contract/${id}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -28,7 +28,7 @@ export const contractDrawingService = {
|
||||
* สร้างแบบสัญญาใหม่
|
||||
*/
|
||||
create: async (data: CreateContractDrawingDto) => {
|
||||
const response = await apiClient.post("/contract-drawings", data);
|
||||
const response = await apiClient.post("/drawings/contract", data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -36,7 +36,7 @@ export const contractDrawingService = {
|
||||
* แก้ไขข้อมูลแบบสัญญา
|
||||
*/
|
||||
update: async (id: string | number, data: UpdateContractDrawingDto) => {
|
||||
const response = await apiClient.put(`/contract-drawings/${id}`, data);
|
||||
const response = await apiClient.put(`/drawings/contract/${id}`, data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -44,7 +44,7 @@ export const contractDrawingService = {
|
||||
* ลบแบบสัญญา (Soft Delete)
|
||||
*/
|
||||
delete: async (id: string | number) => {
|
||||
const response = await apiClient.delete(`/contract-drawings/${id}`);
|
||||
const response = await apiClient.delete(`/drawings/contract/${id}`);
|
||||
return response.data;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
42
frontend/lib/services/dashboard.service.ts
Normal file
42
frontend/lib/services/dashboard.service.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import apiClient from "@/lib/api/client";
|
||||
import { DashboardStats, ActivityLog, PendingTask } from "@/types/dashboard";
|
||||
|
||||
export const dashboardService = {
|
||||
getStats: async (): Promise<DashboardStats> => {
|
||||
const response = await apiClient.get("/dashboard/stats");
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getRecentActivity: async (): Promise<ActivityLog[]> => {
|
||||
try {
|
||||
const response = await apiClient.get("/dashboard/activity");
|
||||
// ตรวจสอบว่า response.data เป็น array จริงๆ
|
||||
if (Array.isArray(response.data)) {
|
||||
return response.data;
|
||||
}
|
||||
console.warn('Dashboard activity: expected array, got:', typeof response.data);
|
||||
return [];
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch recent activity:', error);
|
||||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
getPendingTasks: async (): Promise<PendingTask[]> => {
|
||||
try {
|
||||
const response = await apiClient.get("/dashboard/pending");
|
||||
// Backend คืน { data: [], meta: {} } ต้องดึง data ออกมา
|
||||
if (response.data?.data && Array.isArray(response.data.data)) {
|
||||
return response.data.data;
|
||||
}
|
||||
if (Array.isArray(response.data)) {
|
||||
return response.data;
|
||||
}
|
||||
console.warn('Dashboard pending: unexpected format:', typeof response.data);
|
||||
return [];
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch pending tasks:', error);
|
||||
return [];
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -6,10 +6,11 @@ import { CreateTagDto, UpdateTagDto, SearchTagDto } from "@/types/dto/master/tag
|
||||
import { CreateDisciplineDto } from "@/types/dto/master/discipline.dto";
|
||||
import { CreateSubTypeDto } from "@/types/dto/master/sub-type.dto";
|
||||
import { SaveNumberFormatDto } from "@/types/dto/master/number-format.dto";
|
||||
import { Organization } from "@/types/organization";
|
||||
|
||||
export const masterDataService = {
|
||||
// --- Tags Management ---
|
||||
|
||||
|
||||
/** ดึงรายการ Tags ทั้งหมด (Search & Pagination) */
|
||||
getTags: async (params?: SearchTagDto) => {
|
||||
const response = await apiClient.get("/tags", { params });
|
||||
@@ -34,19 +35,46 @@ export const masterDataService = {
|
||||
return response.data;
|
||||
},
|
||||
|
||||
// --- Organizations (Global) ---
|
||||
|
||||
/** ดึงรายชื่อองค์กรทั้งหมด */
|
||||
getOrganizations: async () => {
|
||||
const response = await apiClient.get<Organization[]>("/organizations");
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** สร้างองค์กรใหม่ */
|
||||
createOrganization: async (data: any) => {
|
||||
const response = await apiClient.post("/organizations", data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** แก้ไของค์กร */
|
||||
updateOrganization: async (id: number, data: any) => {
|
||||
const response = await apiClient.put(`/organizations/${id}`, data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** ลบองค์กร */
|
||||
deleteOrganization: async (id: number) => {
|
||||
const response = await apiClient.delete(`/organizations/${id}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
|
||||
// --- Disciplines Management (Admin / Req 6B) ---
|
||||
|
||||
/** ดึงรายชื่อสาขางาน (มักจะกรองตาม Contract ID) */
|
||||
getDisciplines: async (contractId?: number) => {
|
||||
const response = await apiClient.get("/disciplines", {
|
||||
params: { contractId }
|
||||
const response = await apiClient.get("/master/disciplines", {
|
||||
params: { contractId }
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** สร้างสาขางานใหม่ */
|
||||
createDiscipline: async (data: CreateDisciplineDto) => {
|
||||
const response = await apiClient.post("/disciplines", data);
|
||||
const response = await apiClient.post("/master/disciplines", data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -54,7 +82,7 @@ export const masterDataService = {
|
||||
|
||||
/** ดึงรายชื่อประเภทย่อย (กรองตาม Contract และ Type) */
|
||||
getSubTypes: async (contractId?: number, typeId?: number) => {
|
||||
const response = await apiClient.get("/sub-types", {
|
||||
const response = await apiClient.get("/master/sub-types", {
|
||||
params: { contractId, correspondenceTypeId: typeId }
|
||||
});
|
||||
return response.data;
|
||||
@@ -62,7 +90,7 @@ export const masterDataService = {
|
||||
|
||||
/** สร้างประเภทย่อยใหม่ */
|
||||
createSubType: async (data: CreateSubTypeDto) => {
|
||||
const response = await apiClient.post("/sub-types", data);
|
||||
const response = await apiClient.post("/master/sub-types", data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -81,4 +109,4 @@ export const masterDataService = {
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,48 +1,21 @@
|
||||
// File: lib/services/notification.service.ts
|
||||
import apiClient from "@/lib/api/client";
|
||||
import {
|
||||
SearchNotificationDto,
|
||||
CreateNotificationDto
|
||||
} from "@/types/dto/notification/notification.dto";
|
||||
import { NotificationResponse } from "@/types/notification";
|
||||
|
||||
export const notificationService = {
|
||||
/** * ดึงรายการแจ้งเตือนของผู้ใช้ปัจจุบัน
|
||||
* GET /notifications
|
||||
*/
|
||||
getMyNotifications: async (params?: SearchNotificationDto) => {
|
||||
const response = await apiClient.get("/notifications", { params });
|
||||
getUnread: async (): Promise<NotificationResponse> => {
|
||||
const response = await apiClient.get("/notifications/unread");
|
||||
// Backend should return { items: [], unreadCount: number }
|
||||
// Or just items and we count on frontend, but typically backend gives count.
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** * สร้างการแจ้งเตือนใหม่ (มักใช้โดย System หรือ Admin)
|
||||
* POST /notifications
|
||||
*/
|
||||
create: async (data: CreateNotificationDto) => {
|
||||
const response = await apiClient.post("/notifications", data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** * อ่านแจ้งเตือน (Mark as Read)
|
||||
* PATCH /notifications/:id/read
|
||||
*/
|
||||
markAsRead: async (id: number | string) => {
|
||||
markAsRead: async (id: number) => {
|
||||
const response = await apiClient.patch(`/notifications/${id}/read`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** * อ่านทั้งหมด (Mark All as Read)
|
||||
* PATCH /notifications/read-all
|
||||
*/
|
||||
markAllAsRead: async () => {
|
||||
const response = await apiClient.patch("/notifications/read-all");
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** * ลบการแจ้งเตือน
|
||||
* DELETE /notifications/:id
|
||||
*/
|
||||
delete: async (id: number | string) => {
|
||||
const response = await apiClient.delete(`/notifications/${id}`);
|
||||
const response = await apiClient.patch(`/notifications/read-all`);
|
||||
return response.data;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -10,12 +10,24 @@ export const searchService = {
|
||||
search: async (query: SearchQueryDto) => {
|
||||
// ส่ง params แบบ flat ตาม DTO
|
||||
// GET /search?q=...&type=...&projectId=...
|
||||
const response = await apiClient.get("/search", {
|
||||
params: query
|
||||
const response = await apiClient.get("/search", {
|
||||
params: query
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Suggestion (Autocomplete)
|
||||
* ใช้ search endpoint แต่จำกัดจำนวน
|
||||
*/
|
||||
suggest: async (query: string) => {
|
||||
const response = await apiClient.get("/search", {
|
||||
params: { q: query, limit: 5 }
|
||||
});
|
||||
// Assuming backend returns { items: [], ... } or just []
|
||||
return response.data.items || response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* (Optional) Re-index ข้อมูลใหม่ กรณีข้อมูลไม่ตรง (Admin Only)
|
||||
*/
|
||||
@@ -23,4 +35,4 @@ export const searchService = {
|
||||
const response = await apiClient.post("/search/reindex", { type });
|
||||
return response.data;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// File: lib/services/shop-drawing.service.ts
|
||||
import apiClient from "@/lib/api/client";
|
||||
import {
|
||||
CreateShopDrawingDto,
|
||||
CreateShopDrawingRevisionDto,
|
||||
SearchShopDrawingDto
|
||||
import {
|
||||
CreateShopDrawingDto,
|
||||
CreateShopDrawingRevisionDto,
|
||||
SearchShopDrawingDto
|
||||
} from "@/types/dto/drawing/shop-drawing.dto";
|
||||
|
||||
export const shopDrawingService = {
|
||||
@@ -11,7 +11,7 @@ export const shopDrawingService = {
|
||||
* ดึงรายการแบบก่อสร้าง (Shop Drawings)
|
||||
*/
|
||||
getAll: async (params: SearchShopDrawingDto) => {
|
||||
const response = await apiClient.get("/shop-drawings", { params });
|
||||
const response = await apiClient.get("/drawings/shop", { params });
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -19,7 +19,7 @@ export const shopDrawingService = {
|
||||
* ดึงรายละเอียดตาม ID (ควรได้ Revision History มาด้วย)
|
||||
*/
|
||||
getById: async (id: string | number) => {
|
||||
const response = await apiClient.get(`/shop-drawings/${id}`);
|
||||
const response = await apiClient.get(`/drawings/shop/${id}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -27,7 +27,7 @@ export const shopDrawingService = {
|
||||
* สร้าง Shop Drawing ใหม่ (พร้อม Revision 0)
|
||||
*/
|
||||
create: async (data: CreateShopDrawingDto) => {
|
||||
const response = await apiClient.post("/shop-drawings", data);
|
||||
const response = await apiClient.post("/drawings/shop", data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -35,7 +35,7 @@ export const shopDrawingService = {
|
||||
* สร้าง Revision ใหม่สำหรับ Shop Drawing เดิม
|
||||
*/
|
||||
createRevision: async (id: string | number, data: CreateShopDrawingRevisionDto) => {
|
||||
const response = await apiClient.post(`/shop-drawings/${id}/revisions`, data);
|
||||
const response = await apiClient.post(`/drawings/shop/${id}/revisions`, data);
|
||||
return response.data;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,57 +1,35 @@
|
||||
// File: lib/services/user.service.ts
|
||||
import apiClient from "@/lib/api/client";
|
||||
import {
|
||||
CreateUserDto,
|
||||
UpdateUserDto,
|
||||
AssignRoleDto,
|
||||
UpdatePreferenceDto
|
||||
} from "@/types/dto/user/user.dto";
|
||||
import { CreateUserDto, UpdateUserDto, SearchUserDto, User } from "@/types/user";
|
||||
|
||||
export const userService = {
|
||||
/** ดึงรายชื่อผู้ใช้ทั้งหมด (Admin) */
|
||||
getAll: async (params?: any) => {
|
||||
const response = await apiClient.get("/users", { params });
|
||||
getAll: async (params?: SearchUserDto) => {
|
||||
const response = await apiClient.get<User[]>("/users", { params });
|
||||
// Assuming backend returns array or paginated object.
|
||||
// If backend uses standard pagination { data: [], total: number }, adjust accordingly.
|
||||
// Based on previous code checks, it seems simple array or standard structure.
|
||||
// Let's assume standard response for now.
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** ดึงข้อมูลผู้ใช้ตาม ID */
|
||||
getById: async (id: number | string) => {
|
||||
const response = await apiClient.get(`/users/${id}`);
|
||||
getById: async (id: number) => {
|
||||
const response = await apiClient.get<User>(`/users/${id}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** สร้างผู้ใช้ใหม่ (Admin) */
|
||||
create: async (data: CreateUserDto) => {
|
||||
const response = await apiClient.post("/users", data);
|
||||
const response = await apiClient.post<User>("/users", data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** แก้ไขข้อมูลผู้ใช้ */
|
||||
update: async (id: number | string, data: UpdateUserDto) => {
|
||||
const response = await apiClient.put(`/users/${id}`, data);
|
||||
update: async (id: number, data: UpdateUserDto) => {
|
||||
const response = await apiClient.put<User>(`/users/${id}`, data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** แก้ไขการตั้งค่าส่วนตัว (Preferences) */
|
||||
updatePreferences: async (id: number | string, data: UpdatePreferenceDto) => {
|
||||
const response = await apiClient.put(`/users/${id}/preferences`, data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** * กำหนด Role ให้ผู้ใช้ (Admin)
|
||||
* หมายเหตุ: Backend DTO มี userId ใน body ด้วย แต่ API อาจจะรับ userId ใน param
|
||||
* ขึ้นอยู่กับการ Implement ของ Controller (ในที่นี้ส่งไปทั้งคู่เพื่อความชัวร์)
|
||||
*/
|
||||
assignRole: async (userId: number | string, data: Omit<AssignRoleDto, 'userId'>) => {
|
||||
// รวม userId เข้าไปใน body เพื่อให้ตรงกับ DTO Validation ฝั่ง Backend
|
||||
const payload: AssignRoleDto = { userId: Number(userId), ...data };
|
||||
const response = await apiClient.post(`/users/${userId}/roles`, payload);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** ลบผู้ใช้ (Soft Delete) */
|
||||
delete: async (id: number | string) => {
|
||||
delete: async (id: number) => {
|
||||
const response = await apiClient.delete(`/users/${id}`);
|
||||
return response.data;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
// Optional: Reset Password, Deactivate etc.
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user