262 lines
5.4 KiB
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> |