[회원가입 페이지 추가]
This commit is contained in:
@@ -40,6 +40,14 @@
|
|||||||
<p class="test-account">관리자: admin / stam1201!</p>
|
<p class="test-account">관리자: admin / stam1201!</p>
|
||||||
<p class="test-account">일반 사용자: user / stam1201!</p>
|
<p class="test-account">일반 사용자: user / stam1201!</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 회원 가입 페이지로 이동 링크 -->
|
||||||
|
<div class="register-link">
|
||||||
|
<p>
|
||||||
|
계정이 없으신가요?
|
||||||
|
<NuxtLink to="/register" class="link-text">회원 가입하기</NuxtLink>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -210,6 +218,31 @@ async function signIn() {
|
|||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.register-link {
|
||||||
|
margin-top: 16px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 16px;
|
||||||
|
background: #f8fafc;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-link p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-text {
|
||||||
|
color: #4666e5;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-text:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
@media (max-width: 600px) {
|
||||||
.login-card {
|
.login-card {
|
||||||
padding: 24px 8px 20px 8px;
|
padding: 24px 8px 20px 8px;
|
||||||
|
308
pages/register.vue
Normal file
308
pages/register.vue
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
<template>
|
||||||
|
<div class="register-bg">
|
||||||
|
<div class="register-card">
|
||||||
|
<h1 class="register-title">Integrated Bio Foundry Platform</h1>
|
||||||
|
<div class="register-form">
|
||||||
|
<h2 class="register-signup">회원 가입</h2>
|
||||||
|
|
||||||
|
<!-- 에러 메시지 -->
|
||||||
|
<div v-if="errorMessage" class="error-message">
|
||||||
|
{{ errorMessage }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 성공 메시지 -->
|
||||||
|
<div v-if="successMessage" class="success-message">
|
||||||
|
{{ successMessage }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label class="register-label" for="userId">아이디</label>
|
||||||
|
<input
|
||||||
|
id="userId"
|
||||||
|
v-model="userId"
|
||||||
|
class="register-input"
|
||||||
|
type="text"
|
||||||
|
placeholder="아이디를 입력하세요"
|
||||||
|
:disabled="isLoading"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<label class="register-label" for="password">비밀번호</label>
|
||||||
|
<input
|
||||||
|
id="password"
|
||||||
|
v-model="password"
|
||||||
|
class="register-input"
|
||||||
|
type="password"
|
||||||
|
placeholder="비밀번호를 입력하세요"
|
||||||
|
:disabled="isLoading"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<label class="register-label" for="confirmPassword"
|
||||||
|
>비밀번호 확인</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
id="confirmPassword"
|
||||||
|
v-model="confirmPassword"
|
||||||
|
class="register-input"
|
||||||
|
type="password"
|
||||||
|
placeholder="비밀번호를 다시 입력하세요"
|
||||||
|
:disabled="isLoading"
|
||||||
|
@keyup.enter="signUp"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<button class="register-btn" :disabled="isLoading" @click="signUp">
|
||||||
|
<span v-if="isLoading">가입 중...</span>
|
||||||
|
<span v-else>회원 가입</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- 로그인 페이지로 이동 링크 -->
|
||||||
|
<div class="login-link">
|
||||||
|
<p>
|
||||||
|
이미 계정이 있으신가요?
|
||||||
|
<NuxtLink to="/login" class="link-text">로그인하기</NuxtLink>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
import { useUserStore } from "~/stores/user";
|
||||||
|
|
||||||
|
// auth 레이아웃 사용
|
||||||
|
definePageMeta({
|
||||||
|
layout: "auth",
|
||||||
|
});
|
||||||
|
|
||||||
|
const userId = ref("");
|
||||||
|
const password = ref("");
|
||||||
|
const confirmPassword = ref("");
|
||||||
|
const errorMessage = ref("");
|
||||||
|
const successMessage = ref("");
|
||||||
|
const isLoading = ref(false);
|
||||||
|
const router = useRouter();
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
// 이미 로그인된 경우 홈으로 리다이렉션
|
||||||
|
onMounted(() => {
|
||||||
|
if (userStore.isLoggedIn) {
|
||||||
|
router.push("/");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function signUp() {
|
||||||
|
// 입력값 검증
|
||||||
|
if (!userId.value || !password.value || !confirmPassword.value) {
|
||||||
|
errorMessage.value = "모든 필드를 입력해주세요.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password.value !== confirmPassword.value) {
|
||||||
|
errorMessage.value = "비밀번호가 일치하지 않습니다.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password.value.length < 6) {
|
||||||
|
errorMessage.value = "비밀번호는 최소 6자 이상이어야 합니다.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoading.value = true;
|
||||||
|
errorMessage.value = "";
|
||||||
|
successMessage.value = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
// API 호출을 위한 데이터 준비
|
||||||
|
const registerData = {
|
||||||
|
userId: userId.value,
|
||||||
|
password: password.value,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 실제 API 호출 (여기서는 예시로 구현)
|
||||||
|
const response = await $fetch("/service/members", {
|
||||||
|
method: "POST",
|
||||||
|
body: registerData,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
successMessage.value =
|
||||||
|
"회원 가입이 완료되었습니다! 로그인 페이지로 이동합니다.";
|
||||||
|
|
||||||
|
// 2초 후 로그인 페이지로 이동
|
||||||
|
setTimeout(() => {
|
||||||
|
router.push("/login");
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
if (error.status === 409) {
|
||||||
|
errorMessage.value = "이미 존재하는 아이디입니다.";
|
||||||
|
} else if (error.status === 400) {
|
||||||
|
errorMessage.value = "잘못된 입력값입니다.";
|
||||||
|
} else {
|
||||||
|
errorMessage.value = "회원 가입 중 오류가 발생했습니다.";
|
||||||
|
}
|
||||||
|
console.error("회원 가입 오류:", error);
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.register-bg {
|
||||||
|
width: 100vw;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #f8f9fb;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-card {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 16px 40px 0 rgba(44, 62, 80, 0.08);
|
||||||
|
padding: 40px 36px 32px 36px;
|
||||||
|
min-width: 500px;
|
||||||
|
max-width: 600px;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-title {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
color: #23272f;
|
||||||
|
font-family: "Montserrat", "Pretendard", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-form {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-signup {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
color: #23272f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-label {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
color: #6b7280;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: #f1f5fb;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
font-size: 1rem;
|
||||||
|
outline: none;
|
||||||
|
transition: border 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-input:focus {
|
||||||
|
border: 1.5px solid #4666e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-input:disabled {
|
||||||
|
background: #f3f4f6;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-btn {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 10px 0;
|
||||||
|
background: #4666e5;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 600;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-btn:hover:not(:disabled) {
|
||||||
|
background: #3451b2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-btn:disabled {
|
||||||
|
background: #9ca3af;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
background: #fef2f2;
|
||||||
|
border: 1px solid #fecaca;
|
||||||
|
color: #dc2626;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success-message {
|
||||||
|
background: #f0fdf4;
|
||||||
|
border: 1px solid #bbf7d0;
|
||||||
|
color: #16a34a;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-link {
|
||||||
|
margin-top: 24px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 16px;
|
||||||
|
background: #f8fafc;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-link p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-text {
|
||||||
|
color: #4666e5;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-text:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.register-card {
|
||||||
|
padding: 24px 8px 20px 8px;
|
||||||
|
min-width: 0;
|
||||||
|
max-width: 98vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-title {
|
||||||
|
font-size: 1.3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
Reference in New Issue
Block a user