[회원가입 페이지 추가]
This commit is contained in:
		
							
								
								
									
										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