diff --git a/src/components/outbound/VehicleDispatchManagement/actions.ts b/src/components/outbound/VehicleDispatchManagement/actions.ts index dbf87748..7c8737cc 100644 --- a/src/components/outbound/VehicleDispatchManagement/actions.ts +++ b/src/components/outbound/VehicleDispatchManagement/actions.ts @@ -1,8 +1,5 @@ /** * 배차차량관리 서버 액션 - * - * 현재: Mock 데이터 반환 - * 추후: API 연동 시 serverFetch 사용 */ 'use server'; @@ -13,11 +10,9 @@ import type { VehicleDispatchStats, VehicleDispatchEditFormData, } from './types'; -import { - mockVehicleDispatchItems, - mockVehicleDispatchDetail, - mockVehicleDispatchStats, -} from './mockData'; +import { buildApiUrl } from '@/lib/api/query-params'; +import { executeServerAction } from '@/lib/api/execute-server-action'; +import { executePaginatedAction } from '@/lib/api/execute-paginated-action'; // ===== 페이지네이션 타입 ===== interface PaginationMeta { @@ -27,6 +22,59 @@ interface PaginationMeta { total: number; } +// ===== API 응답 → 프론트 타입 변환 ===== +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function transformToListItem(data: any): VehicleDispatchItem { + const options = data.options || {}; + const shipment = data.shipment || {}; + return { + id: String(data.id), + dispatchNo: options.dispatch_no || `DC-${data.id}`, + shipmentNo: shipment.shipment_no || '', + lotNo: shipment.lot_no || '', + siteName: shipment.site_name || '', + orderCustomer: shipment.customer_name || '', + logisticsCompany: data.logistics_company || '', + tonnage: data.tonnage || '', + supplyAmount: options.supply_amount || 0, + vat: options.vat || 0, + totalAmount: options.total_amount || 0, + freightCostType: options.freight_cost_type || 'prepaid', + vehicleNo: data.vehicle_no || '', + driverContact: data.driver_contact || '', + writer: options.writer || '', + arrivalDateTime: data.arrival_datetime || '', + status: options.status || 'draft', + remarks: data.remarks || '', + }; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function transformToDetail(data: any): VehicleDispatchDetail { + const options = data.options || {}; + const shipment = data.shipment || {}; + return { + id: String(data.id), + dispatchNo: options.dispatch_no || `DC-${data.id}`, + shipmentNo: shipment.shipment_no || '', + lotNo: shipment.lot_no || '', + siteName: shipment.site_name || '', + orderCustomer: shipment.customer_name || '', + freightCostType: options.freight_cost_type || 'prepaid', + status: options.status || 'draft', + writer: options.writer || '', + logisticsCompany: data.logistics_company || '', + arrivalDateTime: data.arrival_datetime || '', + tonnage: data.tonnage || '', + vehicleNo: data.vehicle_no || '', + driverContact: data.driver_contact || '', + remarks: data.remarks || '', + supplyAmount: options.supply_amount || 0, + vat: options.vat || 0, + totalAmount: options.total_amount || 0, + }; +} + // ===== 배차차량 목록 조회 ===== export async function getVehicleDispatches(params?: { page?: number; @@ -41,54 +89,18 @@ export async function getVehicleDispatches(params?: { pagination: PaginationMeta; error?: string; }> { - try { - let items = [...mockVehicleDispatchItems]; - - // 상태 필터 - if (params?.status && params.status !== 'all') { - items = items.filter((item) => item.status === params.status); - } - - // 검색 필터 - if (params?.search) { - const s = params.search.toLowerCase(); - items = items.filter( - (item) => - item.dispatchNo.toLowerCase().includes(s) || - item.shipmentNo.toLowerCase().includes(s) || - item.siteName.toLowerCase().includes(s) || - item.orderCustomer.toLowerCase().includes(s) || - item.vehicleNo.toLowerCase().includes(s) - ); - } - - // 페이지네이션 - const page = params?.page || 1; - const perPage = params?.perPage || 20; - const total = items.length; - const lastPage = Math.ceil(total / perPage); - const startIndex = (page - 1) * perPage; - const paginatedItems = items.slice(startIndex, startIndex + perPage); - - return { - success: true, - data: paginatedItems, - pagination: { - currentPage: page, - lastPage, - perPage, - total, - }, - }; - } catch (error) { - console.error('[VehicleDispatchActions] getVehicleDispatches error:', error); - return { - success: false, - data: [], - pagination: { currentPage: 1, lastPage: 1, perPage: 20, total: 0 }, - error: '서버 오류가 발생했습니다.', - }; - } + return executePaginatedAction({ + url: buildApiUrl('/api/v1/vehicle-dispatches', { + search: params?.search, + status: params?.status !== 'all' ? params?.status : undefined, + start_date: params?.startDate, + end_date: params?.endDate, + page: params?.page, + per_page: params?.perPage, + }), + transform: transformToListItem, + errorMessage: '배차차량 목록 조회에 실패했습니다.', + }); } // ===== 배차차량 통계 조회 ===== @@ -97,12 +109,18 @@ export async function getVehicleDispatchStats(): Promise<{ data?: VehicleDispatchStats; error?: string; }> { - try { - return { success: true, data: mockVehicleDispatchStats }; - } catch (error) { - console.error('[VehicleDispatchActions] getVehicleDispatchStats error:', error); - return { success: false, error: '서버 오류가 발생했습니다.' }; - } + return executeServerAction< + { prepaid_amount: number; collect_amount: number; total_amount: number }, + VehicleDispatchStats + >({ + url: buildApiUrl('/api/v1/vehicle-dispatches/stats'), + transform: (data) => ({ + prepaidAmount: data.prepaid_amount, + collectAmount: data.collect_amount, + totalAmount: data.total_amount, + }), + errorMessage: '배차차량 통계 조회에 실패했습니다.', + }); } // ===== 배차차량 상세 조회 ===== @@ -111,51 +129,34 @@ export async function getVehicleDispatchById(id: string): Promise<{ data?: VehicleDispatchDetail; error?: string; }> { - try { - // Mock: ID로 목록에서 찾아서 상세 데이터 생성 - const item = mockVehicleDispatchItems.find((i) => i.id === id); - if (!item) { - // fallback으로 기본 상세 데이터 반환 - return { success: true, data: { ...mockVehicleDispatchDetail, id } }; - } - - const detail: VehicleDispatchDetail = { - id: item.id, - dispatchNo: item.dispatchNo, - shipmentNo: item.shipmentNo, - siteName: item.siteName, - orderCustomer: item.orderCustomer, - freightCostType: item.freightCostType, - status: item.status, - writer: item.writer, - logisticsCompany: item.logisticsCompany, - arrivalDateTime: item.arrivalDateTime, - tonnage: item.tonnage, - vehicleNo: item.vehicleNo, - driverContact: item.driverContact, - remarks: item.remarks, - supplyAmount: item.supplyAmount, - vat: item.vat, - totalAmount: item.totalAmount, - }; - - return { success: true, data: detail }; - } catch (error) { - console.error('[VehicleDispatchActions] getVehicleDispatchById error:', error); - return { success: false, error: '서버 오류가 발생했습니다.' }; - } + return executeServerAction({ + url: buildApiUrl(`/api/v1/vehicle-dispatches/${id}`), + transform: transformToDetail, + errorMessage: '배차차량 상세 조회에 실패했습니다.', + }); } // ===== 배차차량 수정 ===== export async function updateVehicleDispatch( id: string, - _data: VehicleDispatchEditFormData + data: VehicleDispatchEditFormData ): Promise<{ success: boolean; error?: string }> { - try { - // Mock: 항상 성공 반환 - return { success: true }; - } catch (error) { - console.error('[VehicleDispatchActions] updateVehicleDispatch error:', error); - return { success: false, error: '서버 오류가 발생했습니다.' }; - } + return executeServerAction({ + url: buildApiUrl(`/api/v1/vehicle-dispatches/${id}`), + method: 'PUT', + body: { + freight_cost_type: data.freightCostType, + logistics_company: data.logisticsCompany, + arrival_datetime: data.arrivalDateTime, + tonnage: data.tonnage, + vehicle_no: data.vehicleNo, + driver_contact: data.driverContact, + remarks: data.remarks, + supply_amount: data.supplyAmount, + vat: data.vat, + total_amount: data.totalAmount, + status: undefined, // 상태는 별도로 관리 + }, + errorMessage: '배차차량 수정에 실패했습니다.', + }); }