[UI 개선] 서브메뉴 및 탭 바 컴포넌트 추가, AppHeader 및 기본 레이아웃 수정, API 호출 로직 개선

This commit is contained in:
2025-09-24 16:25:30 +09:00
parent f83782813d
commit f9dde4eb09
10 changed files with 338 additions and 490 deletions

View File

@@ -7,17 +7,20 @@
* @returns Promise<T> - API 응답 데이터
*
* @example
* // GET 요청 (기본)
* // GET 요청 (기본 - 전역 로딩 자동 적용)
* const users = await useApi<User[]>('/users')
*
* // POST 요청
* // POST 요청 (커스텀 로딩 메시지)
* const newUser = await useApi<User>('/users', {
* method: 'POST',
* body: { name: 'John', email: 'john@example.com' }
* body: { name: 'John', email: 'john@example.com' },
* loadingMessage: '사용자를 생성하는 중...'
* })
*
* // 에러 시 alert 표시
* const data = await useApi<User[]>('/users', { showAlert: true })
* // 전역 로딩 없이 API 호출
* const data = await useApi<User[]>('/users', {
* useGlobalLoading: false
* })
*
* // 에러를 직접 처리
* try {
@@ -29,7 +32,11 @@
* // FormData 업로드
* const formData = new FormData()
* formData.append('file', file)
* await useApi('/upload', { method: 'POST', body: formData })
* await useApi('/upload', {
* method: 'POST',
* body: formData,
* loadingMessage: '파일을 업로드하는 중...'
* })
*/
export const useApi = async <T>(
path: string,
@@ -41,50 +48,72 @@ export const useApi = async <T>(
// 에러 처리 옵션
handleError?: boolean; // true: 에러를 null로 반환, false: 에러를 다시 던짐
showAlert?: boolean; // true: 에러 시 alert 표시
// 로딩 옵션
loadingMessage?: string; // 로딩 메시지
useGlobalLoading?: boolean; // 전역 로딩 사용 여부 (기본값: true)
}
): Promise<T> => {
const { $api } = useNuxtApp();
const { withLoading } = useLoading();
// 기본값 설정
const {
method = "GET",
body,
headers,
handleError = true,
showAlert = true,
} = options || {};
// API 호출 로직을 별도 함수로 분리
const apiCall = async (): Promise<T> => {
const { $api } = useNuxtApp();
// API 요청 옵션 구성
const apiOpts = {
method,
...(body && { body }),
...(headers && { headers }),
};
// 기본값 설정
const {
method = "GET",
body,
headers,
handleError = true,
showAlert = true,
} = options || {};
return ($api as any)(path, apiOpts).catch((error: any) => {
// 사용자에게 알림 표시
if (showAlert) {
const status = error.response?.status;
let message =
status === 404
? "요청한 리소스를 찾을 수 없습니다."
: status === 500
? "서버 오류가 발생했습니다."
: "요청 처리 중 오류가 발생했습니다.";
// API 요청 옵션 구성
const apiOpts = {
method,
...(body && { body }),
...(headers && { headers }),
};
// 서버에서 온 에러 메시지가 있으면 우선 사용
if (error.response?._data?.description) {
message = error.response._data.description;
return ($api as any)(path, apiOpts).catch((error: any) => {
// 사용자에게 알림 표시
if (showAlert) {
const status = error.response?.status;
let message =
status === 404
? "요청한 리소스를 찾을 수 없습니다."
: status === 500
? "서버 오류가 발생했습니다."
: "요청 처리 중 오류가 발생했습니다.";
// 서버에서 온 에러 메시지가 있으면 우선 사용
if (error.response?._data?.description) {
message = error.response._data.description;
}
alert(message);
}
alert(message);
}
// 에러 처리 방식에 따라 반환
if (handleError) {
return null as T; // 에러를 null로 반환
} else {
throw error; // 에러를 다시 던짐
}
});
};
// 에러 처리 방식에 따라 반환
if (handleError) {
return null as T; // 에러를 null로 반환
} else {
throw error; // 에러를 다시 던짐
}
});
// 전역 로딩 사용 여부 확인 (기본값: true)
const shouldUseLoading = options?.useGlobalLoading !== false;
if (shouldUseLoading) {
// 전역 로딩과 함께 API 호출
return await withLoading(
apiCall,
options?.loadingMessage || "데이터를 불러오는 중..."
);
} else {
// 전역 로딩 없이 API 호출
return await apiCall();
}
};