[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