[API 통신 보완] $fetch방식으로 변경 및 로그인 처리 보완완
This commit is contained in:
		@@ -33,7 +33,7 @@
 | 
				
			|||||||
    <!-- 사용자 정보 및 드롭다운 -->
 | 
					    <!-- 사용자 정보 및 드롭다운 -->
 | 
				
			||||||
    <div class="user-menu-wrapper">
 | 
					    <div class="user-menu-wrapper">
 | 
				
			||||||
      <div class="user-info" @click="toggleDropdown">
 | 
					      <div class="user-info" @click="toggleDropdown">
 | 
				
			||||||
        <span class="user-name">{{ userStore.userName }}</span>
 | 
					        <span class="user-name">{{ userStore.user?.name }}</span>
 | 
				
			||||||
        <div class="user-icon">
 | 
					        <div class="user-icon">
 | 
				
			||||||
          <svg
 | 
					          <svg
 | 
				
			||||||
            width="24"
 | 
					            width="24"
 | 
				
			||||||
@@ -128,7 +128,9 @@ onBeforeUnmount(() => {
 | 
				
			|||||||
  border: none;
 | 
					  border: none;
 | 
				
			||||||
  padding: 0.5rem 1.5rem;
 | 
					  padding: 0.5rem 1.5rem;
 | 
				
			||||||
  border-radius: 6px;
 | 
					  border-radius: 6px;
 | 
				
			||||||
  transition: background 0.15s, color 0.15s;
 | 
					  transition:
 | 
				
			||||||
 | 
					    background 0.15s,
 | 
				
			||||||
 | 
					    color 0.15s;
 | 
				
			||||||
  cursor: pointer;
 | 
					  cursor: pointer;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.menu-btn.active {
 | 
					.menu-btn.active {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,33 +1,45 @@
 | 
				
			|||||||
import { useFetch, useRuntimeConfig } from '#imports';
 | 
					import { useRuntimeConfig } from "#imports";
 | 
				
			||||||
 | 
					import { useUserStore } from "~/stores/user";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useApi = <T>(
 | 
					export const useApi = async <T>(
 | 
				
			||||||
  path: string,
 | 
					  path: string,
 | 
				
			||||||
  options: {
 | 
					  options: {
 | 
				
			||||||
    method?: 'get' | 'post' | 'put' | 'delete'
 | 
					    method?: "get" | "post" | "put" | "delete";
 | 
				
			||||||
    body?: any
 | 
					    body?: any;
 | 
				
			||||||
    query?: Record<string, any>
 | 
					    query?: Record<string, any>;
 | 
				
			||||||
    headers?: HeadersInit
 | 
					    headers?: HeadersInit;
 | 
				
			||||||
    server?: boolean // ← 이 줄 추가!
 | 
					 | 
				
			||||||
  } = {}
 | 
					  } = {}
 | 
				
			||||||
) => {
 | 
					): Promise<T> => {
 | 
				
			||||||
  const userStore = useUserStore();
 | 
					  const userStore = useUserStore();
 | 
				
			||||||
 | 
					 | 
				
			||||||
  const config = useRuntimeConfig();
 | 
					  const config = useRuntimeConfig();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const method = options.method ? options.method.toUpperCase() : 'GET'
 | 
					  const method = options.method ? options.method.toUpperCase() : "GET";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return useFetch<T>(() => `${config.public.apiBase}${config.public.contextPath}${path}`, {
 | 
					  try {
 | 
				
			||||||
    method: method as any, // 타입 강제 우회
 | 
					    const response = await $fetch<T>(
 | 
				
			||||||
    body: options.body,
 | 
					      `${config.public.apiBase}${config.public.contextPath}${path}`,
 | 
				
			||||||
    query: options.query,
 | 
					      {
 | 
				
			||||||
    headers: {
 | 
					        method: method as any,
 | 
				
			||||||
      Authorization: 'Bearer ' + userStore.getToken,
 | 
					        body: options.body,
 | 
				
			||||||
      ...options.headers,
 | 
					        query: options.query,
 | 
				
			||||||
    },
 | 
					        headers: {
 | 
				
			||||||
    onResponse({response}){    
 | 
					          Authorization: "Bearer " + userStore.token,
 | 
				
			||||||
      const accessToken = response.headers.get("Authorization") || "";
 | 
					          ...options.headers,
 | 
				
			||||||
      userStore.setToken(accessToken.replace("Bearer ", ""));
 | 
					        },
 | 
				
			||||||
    },
 | 
					        onResponse({ response }) {
 | 
				
			||||||
    server: options.server // ← 이 줄 추가!
 | 
					          const authHeader = response.headers.get("Authorization");
 | 
				
			||||||
  })
 | 
					
 | 
				
			||||||
}
 | 
					          if (authHeader && authHeader.startsWith("Bearer ")) {
 | 
				
			||||||
 | 
					            const accessToken = authHeader.substring(7);
 | 
				
			||||||
 | 
					            userStore.setToken(accessToken);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return response;
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    console.error("API 호출 실패:", error);
 | 
				
			||||||
 | 
					    throw error;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,7 +19,7 @@
 | 
				
			|||||||
          <p class="text-lg text-gray-800 mb-2">
 | 
					          <p class="text-lg text-gray-800 mb-2">
 | 
				
			||||||
            안녕하세요,
 | 
					            안녕하세요,
 | 
				
			||||||
            <span class="font-semibold text-blue-600">{{
 | 
					            <span class="font-semibold text-blue-600">{{
 | 
				
			||||||
              userStore.userName
 | 
					              userStore.user?.name
 | 
				
			||||||
            }}</span
 | 
					            }}</span
 | 
				
			||||||
            >님!
 | 
					            >님!
 | 
				
			||||||
          </p>
 | 
					          </p>
 | 
				
			||||||
@@ -28,7 +28,15 @@
 | 
				
			|||||||
            로그인되었습니다.
 | 
					            로그인되었습니다.
 | 
				
			||||||
          </p>
 | 
					          </p>
 | 
				
			||||||
          <p class="text-sm text-gray-600">
 | 
					          <p class="text-sm text-gray-600">
 | 
				
			||||||
            <button @click="useApi<ApiResponse<{}>>('/files/download/1756167537354001',{method: 'get'});" > Test</button>
 | 
					            <button
 | 
				
			||||||
 | 
					              @click="
 | 
				
			||||||
 | 
					                useApi<ApiResponse<{}>>('/files/download/1756167537354001', {
 | 
				
			||||||
 | 
					                  method: 'get',
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					              "
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              Test
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
          </p>
 | 
					          </p>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <div
 | 
					        <div
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,53 +2,46 @@ export const useUserStore = defineStore("user", () => {
 | 
				
			|||||||
  // 상태
 | 
					  // 상태
 | 
				
			||||||
  const isLoggedIn = ref(false);
 | 
					  const isLoggedIn = ref(false);
 | 
				
			||||||
  const user = ref<{
 | 
					  const user = ref<{
 | 
				
			||||||
    id?: string;
 | 
					 | 
				
			||||||
    userId?: string;
 | 
					    userId?: string;
 | 
				
			||||||
    email?: string;
 | 
					 | 
				
			||||||
    name?: string;
 | 
					    name?: string;
 | 
				
			||||||
    role?: string;
 | 
					 | 
				
			||||||
  } | null>(null);
 | 
					  } | null>(null);
 | 
				
			||||||
  const token = ref<string | null>(null);
 | 
					  const token = ref<string | null>(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 추후 제거 필요
 | 
				
			||||||
 | 
					  const isAdmin = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  interface LoginData {
 | 
					  interface LoginData {
 | 
				
			||||||
    userId: string
 | 
					    userId: string;
 | 
				
			||||||
    role: string
 | 
					 | 
				
			||||||
    lastLoginAt: string
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  // 게터
 | 
					 | 
				
			||||||
  const isAdmin = computed(() => user.value?.role === "admin");
 | 
					 | 
				
			||||||
  const userName = computed(() => user.value?.name || "사용자");
 | 
					 | 
				
			||||||
  // 액션
 | 
					  // 액션
 | 
				
			||||||
  const login = async (userId: string, password: string) => {
 | 
					  const login = async (userId: string, password: string) => {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      // 실제 API 호출로 대체할 수 있습니다
 | 
					      // 실제 API 호출로 대체할 수 있습니다
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const {data, error: _error } = await useApi<ApiResponse<LoginData>>('/login', {
 | 
					      const { success, data } = await useApi<ApiResponse<LoginData>>("/login", {
 | 
				
			||||||
        method: 'post',
 | 
					        method: "post",
 | 
				
			||||||
        body: { userId, password }
 | 
					        body: { userId, password },
 | 
				
			||||||
      })     
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      let mockUser;
 | 
					      if (success) {
 | 
				
			||||||
 | 
					        console.log(data);
 | 
				
			||||||
      if(data && data.value && data.value.success){
 | 
					        user.value = data;
 | 
				
			||||||
        mockUser = data.value.data;
 | 
					        isLoggedIn.value = true;
 | 
				
			||||||
      }else{
 | 
					      } else {
 | 
				
			||||||
        throw new Error("아이디 또는 비밀번호가 올바르지 않습니다.");
 | 
					        throw new Error("아이디 또는 비밀번호가 올바르지 않습니다.");
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      user.value = mockUser;
 | 
					      return { success };
 | 
				
			||||||
      // token.value = "mock-token-" + Date.now();
 | 
					    } catch (error: any) {
 | 
				
			||||||
      isLoggedIn.value = true;
 | 
					      console.log(error);
 | 
				
			||||||
 | 
					 | 
				
			||||||
      return { success: true, user: mockUser };
 | 
					 | 
				
			||||||
    } catch (error) {
 | 
					 | 
				
			||||||
      console.error("로그인 실패:", error);
 | 
					 | 
				
			||||||
      return {
 | 
					      return {
 | 
				
			||||||
        success: false,
 | 
					        success: false,
 | 
				
			||||||
        error:
 | 
					        error:
 | 
				
			||||||
          error instanceof Error ? error.message : "로그인에 실패했습니다.",
 | 
					          error?.response?.status === 401
 | 
				
			||||||
 | 
					            ? "아이디 또는 비밀번호가 올바르지 않습니다."
 | 
				
			||||||
 | 
					            : error instanceof Error
 | 
				
			||||||
 | 
					              ? error.message
 | 
				
			||||||
 | 
					              : "로그인에 실패했습니다.",
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
@@ -75,13 +68,13 @@ export const useUserStore = defineStore("user", () => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const setToken = (accessToken : string) => {
 | 
					  const setToken = (accessToken: string) => {
 | 
				
			||||||
    token.value = accessToken;
 | 
					    token.value = accessToken;
 | 
				
			||||||
  }
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const getToken = () => {
 | 
					  const getToken = () => {
 | 
				
			||||||
    return token;
 | 
					    return token;
 | 
				
			||||||
  }
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // 초기 인증 상태 확인
 | 
					  // 초기 인증 상태 확인
 | 
				
			||||||
  if (import.meta.client) {
 | 
					  if (import.meta.client) {
 | 
				
			||||||
@@ -96,13 +89,12 @@ export const useUserStore = defineStore("user", () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // 게터
 | 
					    // 게터
 | 
				
			||||||
    isAdmin,
 | 
					    isAdmin,
 | 
				
			||||||
    userName,
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 액션
 | 
					    // 액션
 | 
				
			||||||
    login,
 | 
					    login,
 | 
				
			||||||
    logout,
 | 
					    logout,
 | 
				
			||||||
    checkAuth,
 | 
					    checkAuth,
 | 
				
			||||||
    setToken,
 | 
					    setToken,
 | 
				
			||||||
    getToken
 | 
					    getToken,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user