dramaling-app/apps/web/src/views/auth/RegisterView.vue

262 lines
5.4 KiB
Vue

<template>
<div class="register-view">
<BaseCard class="register-card">
<h2 class="register-title">加入 Drama Ling</h2>
<p class="register-subtitle">開始你的語言學習之旅</p>
<form @submit.prevent="handleRegister" class="register-form">
<BaseInput
v-model="form.username"
type="text"
label="用戶名稱"
placeholder="請輸入用戶名稱"
:error="errors.username"
:disabled="isLoading"
required
/>
<BaseInput
v-model="form.email"
type="email"
label="電子郵件"
placeholder="請輸入電子郵件地址"
:error="errors.email"
:disabled="isLoading"
required
/>
<BaseInput
v-model="form.password"
type="password"
label="密碼"
placeholder="請輸入密碼(至少 8 個字元)"
:error="errors.password"
:disabled="isLoading"
required
/>
<BaseInput
v-model="form.confirmPassword"
type="password"
label="確認密碼"
placeholder="請再次輸入密碼"
:error="errors.confirmPassword"
:disabled="isLoading"
required
/>
<div class="terms-checkbox">
<label class="checkbox-wrapper">
<input
type="checkbox"
v-model="form.agreeToTerms"
:disabled="isLoading"
/>
<span class="checkbox-text">
我同意
<a href="/terms" target="_blank" class="terms-link">使用條款</a>
<a href="/privacy" target="_blank" class="terms-link">隱私政策</a>
</span>
</label>
<div v-if="errors.terms" class="error-text">{{ errors.terms }}</div>
</div>
<BaseButton
type="submit"
variant="primary"
size="lg"
:disabled="!canSubmit"
>
註冊帳戶
</BaseButton>
<div class="divider">
<span>或</span>
</div>
<BaseButton
variant="outline"
size="lg"
:disabled="isLoading"
@click="handleGoogleRegister"
>
使用 Google 註冊
</BaseButton>
</form>
<div class="login-prompt">
已經有帳戶了?
<router-link to="/auth/login" class="login-link">
立即登入
</router-link>
</div>
</BaseCard>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, computed } from 'vue'
import { useRouter } from 'vue-router'
import BaseCard from '@/components/base/BaseCard.vue'
import BaseInput from '@/components/base/BaseInput.vue'
import BaseButton from '@/components/base/BaseButton.vue'
import { isValidEmail } from '@/utils'
const router = useRouter()
// 表單狀態
const form = reactive({
username: '',
email: '',
password: '',
confirmPassword: '',
agreeToTerms: false
})
const errors = reactive({
username: '',
email: '',
password: '',
confirmPassword: '',
terms: ''
})
const isLoading = ref(false)
// 計算屬性
const canSubmit = computed(() => {
return form.username &&
form.email &&
form.password &&
form.confirmPassword &&
form.agreeToTerms &&
isValidEmail(form.email) &&
form.password === form.confirmPassword &&
form.password.length >= 8 &&
!isLoading.value
})
const handleRegister = async () => {
console.log('註冊表單提交:', form)
alert('註冊功能開發中')
}
const handleGoogleRegister = async () => {
alert('Google 註冊功能開發中')
}
</script>
<style scoped>
.register-view {
width: 100%;
max-width: 450px;
margin: 0 auto;
}
.register-card {
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(74, 85, 104, 0.2);
backdrop-filter: blur(10px);
}
.register-title {
font-size: 1.5rem;
font-weight: 700;
color: #FFFFFF;
margin: 0 0 0.5rem 0;
text-align: center;
}
.register-subtitle {
font-size: 0.875rem;
color: #B8BCC8;
margin: 0 0 2rem 0;
text-align: center;
}
.register-form {
display: flex;
flex-direction: column;
gap: 1.25rem;
}
.terms-checkbox {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.checkbox-wrapper {
display: flex;
align-items: center;
gap: 0.5rem;
cursor: pointer;
font-size: 0.875rem;
line-height: 1.5;
}
.checkbox-text {
color: #B8BCC8;
}
.terms-link {
color: #00E5CC;
text-decoration: none;
}
.terms-link:hover {
text-decoration: underline;
}
.error-text {
font-size: 0.75rem;
color: #EF4444;
margin-top: 0.25rem;
}
.divider {
position: relative;
text-align: center;
margin: 1rem 0;
}
.divider::before {
content: '';
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 1px;
background: #4A5568;
}
.divider span {
background: #3A4A5C;
padding: 0 1rem;
font-size: 0.875rem;
color: #B8BCC8;
}
.login-prompt {
text-align: center;
font-size: 0.875rem;
color: #B8BCC8;
margin-top: 1.5rem;
padding-top: 1.5rem;
border-top: 1px solid #4A5568;
}
.login-link {
color: #00E5CC;
text-decoration: none;
font-weight: 600;
margin-left: 0.25rem;
transition: color 0.3s ease;
}
.login-link:hover {
color: #33E8D1;
text-decoration: underline;
}
</style>