fix: 품목관리 API 응답 파싱 및 필드명 수정

- ApiItem 인터페이스: code → item_code 변경 (API 응답 구조 반영)
- transformItem: item_code 필드 사용하도록 수정
- transformItemToApi: item_type → product_type으로 변경 (API 요청 필드명)
- getItemList: Laravel 페이지네이션 응답 구조 처리 개선
- getItem: API 응답 구조(success, message, data) 처리
- getCategoryOptions: 페이지네이션 응답 파싱 수정
- createItem: 응답에서 ID 추출 로직 개선
- 디버깅용 console.log 추가
This commit is contained in:
2026-01-14 20:04:44 +09:00
parent ebc7320eeb
commit 6dc91daaca

View File

@@ -88,7 +88,7 @@ function transformOrderItems(options: Record<string, unknown> | null | undefined
*/
interface ApiItem {
id: number;
code: string;
item_code: string; // API가 'code' 대신 'item_code'로 반환 (ApiResponse 충돌 방지)
name: string;
item_type: string | null;
category_id: number | null;
@@ -104,7 +104,7 @@ interface ApiItem {
function transformItem(apiItem: ApiItem): Item {
return {
id: String(apiItem.id),
itemNumber: apiItem.code || '',
itemNumber: apiItem.item_code || '',
itemName: apiItem.name || '',
itemType: transformItemType(apiItem.item_type),
categoryId: apiItem.category_id ? String(apiItem.category_id) : '',
@@ -136,7 +136,7 @@ function transformItemToApi(data: ItemFormData): Record<string, unknown> {
return {
code: data.itemNumber,
name: data.itemName,
item_type: transformToBackendItemType(data.itemType),
product_type: transformToBackendItemType(data.itemType),
category_id: data.categoryId ? parseInt(data.categoryId, 10) : null,
unit: data.unit,
is_active: data.status === '사용' || data.status === '승인',
@@ -161,6 +161,7 @@ function transformItemToApi(data: ItemFormData): Record<string, unknown> {
export async function getItemList(
params: ItemListParams = {}
): Promise<{ success: boolean; data?: ItemListResponse; error?: string }> {
console.log('📥 [getItemList] 호출됨, params:', params);
try {
const queryParams: Record<string, string> = {};
@@ -186,21 +187,59 @@ export async function getItemList(
queryParams.active = params.status === '사용' || params.status === '승인' ? '1' : '0';
}
console.log('📤 [getItemList] API 호출:', queryParams);
const response = await apiClient.get<{
data: ApiItem[];
meta?: { total: number; current_page: number; per_page: number };
total?: number;
current_page?: number;
per_page?: number;
last_page?: number;
per_page?: number;
}>('/items', { params: queryParams });
console.log('📥 [getItemList] API 응답:', JSON.stringify(response).slice(0, 500));
// API 응답 구조 처리 (data 배열 또는 페이지네이션 객체)
const items = Array.isArray(response.data) ? response.data : (response.data as unknown as ApiItem[]);
const meta = response.meta || {
total: response.total || items.length,
current_page: response.current_page || params.page || 1,
per_page: response.per_page || params.size || 20,
};
// API 응답 구조 처리
// Laravel 페이지네이션 응답: { current_page, data: [...], last_page, per_page, total, ... }
// data 필드가 배열인 경우와 페이지네이션 객체인 경우 모두 처리
let items: ApiItem[];
let meta: { total: number; current_page: number; per_page: number };
if (Array.isArray(response.data)) {
// response.data가 직접 배열인 경우
items = response.data;
meta = response.meta || {
total: response.total || items.length,
current_page: response.current_page || params.page || 1,
per_page: response.per_page || params.size || 20,
};
} else if (response.data && Array.isArray((response as unknown as { data: { data: ApiItem[] } }).data.data)) {
// response가 { data: { current_page, data: [...], ... } } 형태인 경우 (Laravel 페이지네이션)
const paginatedResponse = response as unknown as {
data: { data: ApiItem[]; current_page: number; total: number; per_page: number };
};
items = paginatedResponse.data.data;
meta = {
total: paginatedResponse.data.total || items.length,
current_page: paginatedResponse.data.current_page || params.page || 1,
per_page: paginatedResponse.data.per_page || params.size || 20,
};
} else if (response.current_page !== undefined && Array.isArray((response as unknown as { data: ApiItem[] }).data)) {
// response가 { current_page, data: [...], total, per_page } 형태인 경우
items = (response as unknown as { data: ApiItem[] }).data;
meta = {
total: response.total || items.length,
current_page: response.current_page || params.page || 1,
per_page: response.per_page || params.size || 20,
};
} else {
// 예상치 못한 응답 구조
console.error('❌ [getItemList] 예상치 못한 응답 구조:', response);
items = [];
meta = { total: 0, current_page: 1, per_page: 20 };
}
console.log('📊 [getItemList] 파싱된 items 수:', items.length, ', meta:', meta);
// Frontend 필터링 (Backend에서 지원하지 않는 필터)
let transformedItems = items.map(transformItem);
@@ -248,7 +287,7 @@ export async function getItemList(
},
};
} catch (error) {
console.error('품목 목록 조회 오류:', error);
console.error('❌ [getItemList] 오류:', error);
return { success: false, error: '품목 목록을 불러오는데 실패했습니다.' };
}
}
@@ -318,10 +357,23 @@ export async function getCategoryOptions(): Promise<{
}> {
try {
const response = await apiClient.get<{
data: { id: number; name: string }[];
success: boolean;
message: string;
data: {
current_page: number;
data: { id: number; name: string }[];
total: number;
};
}>('/categories', { params: { size: 100 } });
const categories = response.data.map((cat) => ({
// API 응답 구조: { success, message, data: { current_page, data: [...], ... } }
const categoryData = response.data?.data;
if (!Array.isArray(categoryData)) {
console.error('카테고리 응답 구조 오류:', response);
return { success: true, data: [] };
}
const categories = categoryData.map((cat) => ({
id: String(cat.id),
name: cat.name,
}));
@@ -343,9 +395,17 @@ export async function getItem(id: string): Promise<{
error?: string;
}> {
try {
const response = await apiClient.get<ApiItem>(`/items/${id}`);
const response = await apiClient.get<{ success: boolean; message: string; data: ApiItem }>(`/items/${id}`);
console.log('📥 [getItem] API 응답:', JSON.stringify(response).slice(0, 300));
return { success: true, data: transformItemDetail(response) };
// API 응답 구조: { success, message, data: {...item...} }
const item = response.data;
if (!item) {
console.error('❌ [getItem] 응답에 data가 없음:', response);
return { success: false, error: '품목 정보를 찾을 수 없습니다.' };
}
return { success: true, data: transformItemDetail(item) };
} catch (error) {
console.error('품목 상세 조회 오류:', error);
return { success: false, error: '품목 정보를 불러오는데 실패했습니다.' };
@@ -362,12 +422,21 @@ export async function createItem(data: ItemFormData): Promise<{
error?: string;
}> {
try {
console.log('📤 [createItem] 입력 데이터:', data);
const apiData = transformItemToApi(data);
const response = await apiClient.post<{ id: number }>('/items', apiData);
console.log('📤 [createItem] 변환된 API 데이터:', apiData);
const response = await apiClient.post<{ success: boolean; data: { id: number }; id?: number }>('/items', apiData);
console.log('📥 [createItem] API 응답:', response);
return { success: true, data: { id: String(response.id) } };
// API 응답 구조: { success, message, data: { id } } 또는 { id }
const itemId = response.data?.id ?? response.id;
if (!itemId) {
console.error('❌ [createItem] 응답에서 ID를 찾을 수 없음:', response);
return { success: false, error: '품목 등록 후 ID를 가져오지 못했습니다.' };
}
return { success: true, data: { id: String(itemId) } };
} catch (error) {
console.error('품목 등록 오류:', error);
console.error('❌ [createItem] 품목 등록 오류:', error);
return { success: false, error: '품목 등록에 실패했습니다.' };
}
}