Files
tyapi-frontend/src/pages/sub-portal/SubRegister.vue

149 lines
4.6 KiB
Vue
Raw Normal View History

2026-04-25 11:59:14 +08:00
<template>
<div class="w-full auth-fade-in">
<div class="text-center mb-6">
<h2 class="auth-title">子账号注册</h2>
<p class="auth-subtitle">填写邀请码与手机号完成成员账号开通</p>
</div>
<form class="space-y-4" @submit.prevent="onRegister">
<div>
<label class="auth-label">邀请码 <span class="text-red-500">*</span></label>
<el-input v-model="form.inviteToken" placeholder="请输入主账号提供的邀请码" size="large" clearable :disabled="loading"
class="auth-input" />
</div>
<div>
<label class="auth-label">手机号</label>
<el-input v-model="form.phone" maxlength="11" placeholder="手机号" size="large" :disabled="loading" class="auth-input" />
</div>
<div>
<label class="auth-label">验证码</label>
<div class="flex gap-3">
<el-input v-model="form.code" maxlength="6" placeholder="短信验证码" size="large" :disabled="loading" class="auth-input" />
<el-button type="primary" size="large" :disabled="!canSendCode || loading" :loading="sendingCode"
class="auth-button !min-w-[120px]" @click="sendCode">
{{ countdown > 0 ? `${countdown}s` : '获取验证码' }}
</el-button>
</div>
</div>
<div>
<label class="auth-label">密码</label>
<el-input v-model="form.password" type="password" show-password size="large" :disabled="loading" class="auth-input" />
</div>
<div>
<label class="auth-label">确认密码</label>
<el-input v-model="form.confirmPassword" type="password" show-password size="large" :disabled="loading"
class="auth-input" />
</div>
<div class="text-center">
<router-link to="/sub/auth/login" class="auth-link text-sm">返回登录</router-link>
</div>
<el-button type="primary" size="large" class="auth-button w-full !h-12" native-type="submit" :loading="loading"
:disabled="!canSubmit">
注册
</el-button>
</form>
<p class="mt-4 text-xs text-center text-slate-400">
请确保邀请码来自可信主账号避免账号安全风险
</p>
</div>
</template>
<script setup>
import { subPortalApi } from '@/api'
import { useAliyunCaptcha } from '@/composables/useAliyunCaptcha'
import { useUserStore } from '@/stores/user'
import { ElMessage } from 'element-plus'
const route = useRoute()
const router = useRouter()
const userStore = useUserStore()
const { runWithCaptcha } = useAliyunCaptcha()
const form = ref({
inviteToken: '',
phone: '',
code: '',
password: '',
confirmPassword: ''
})
const loading = ref(false)
const sendingCode = ref(false)
const countdown = ref(0)
let timer = null
// 与主站同仓同构建:链接 ?invite= 或主账号复制的完整 URL 均会打开本页并预填邀请码
watch(
() => route.query.invite,
(inv) => {
if (typeof inv === 'string' && inv) {
form.value.inviteToken = inv
}
},
{ immediate: true }
)
const canSendCode = computed(
() => form.value.phone?.length === 11 && countdown.value === 0
)
const canSubmit = computed(
() =>
form.value.inviteToken &&
form.value.phone?.length === 11 &&
form.value.code?.length === 6 &&
form.value.password?.length >= 6 &&
form.value.password === form.value.confirmPassword
)
const sendCode = async () => {
if (!canSendCode.value) return
sendingCode.value = true
try {
await runWithCaptcha(
async (captcha) => userStore.sendCode(form.value.phone, 'register', captcha),
(res) => {
if (res.success) {
ElMessage.success('验证码已发送')
countdown.value = 60
timer = setInterval(() => {
countdown.value--
if (countdown.value <= 0) clearInterval(timer)
}, 1000)
} else {
ElMessage.error(res?.error?.message || '发送失败')
}
}
)
} finally {
sendingCode.value = false
}
}
const onRegister = async () => {
if (!canSubmit.value) return
loading.value = true
try {
const res = await subPortalApi.register({
phone: form.value.phone,
password: form.value.password,
confirm_password: form.value.confirmPassword,
code: form.value.code,
invite_token: form.value.inviteToken
})
if (res?.success) {
ElMessage.success('注册成功,请登录')
router.push('/sub/auth/login')
}
} catch (e) {
ElMessage.error(e?.response?.data?.message || e?.message || '注册失败')
} finally {
loading.value = false
}
}
onUnmounted(() => {
if (timer) clearInterval(timer)
})
</script>