Files
client-web/src/modules/auth/views/RegisterView.vue
T
2026-09-11 16:17:24 +08:00

162 lines
9.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { nextTick, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
import { CheckCircle2, Mail, Phone } from '@lucide/vue'
import { registerMerchant } from '@/modules/auth/api/auth'
import AuthShell from '@/modules/auth/components/AuthShell.vue'
interface RegisterForm {
username: string
companyName: string
displayName: string
legalPerson: string
phone: string
contactEmail: string
countryCode: string
address: string
password: string
agreement: boolean
}
const router = useRouter()
const formRef = ref<FormInstance>()
const submitting = ref(false)
const submitted = ref(false)
const submittedAt = ref('')
const form = reactive<RegisterForm>({ username: '', companyName: '', displayName: '', legalPerson: '', phone: '', contactEmail: '', countryCode: 'CN', address: '', password: '', agreement: false })
const rules: FormRules<RegisterForm> = {
username: [
{ required: true, message: '请输入登录用户名', trigger: 'blur' },
{ pattern: /^[A-Za-z][A-Za-z0-9_.@-]{3,63}$/, message: '用户名须以字母开头,并由 4–64 位字母、数字或 _.@- 组成', trigger: 'blur' },
],
companyName: [
{ required: true, message: '请输入企业名称', trigger: 'blur' },
{ min: 2, max: 100, message: '企业名称长度应为 2–100 个字符', trigger: 'blur' },
],
displayName: [
{ required: true, message: '请输入联系人姓名', trigger: 'blur' },
{ max: 64, message: '联系人姓名最多 64 个字符', trigger: 'blur' },
],
legalPerson: [
{ max: 64, message: '法定代表人最多 64 个字符', trigger: 'blur' },
],
contactEmail: [
{ type: 'email', message: '请输入有效的邮箱地址', trigger: 'blur' },
],
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{ pattern: /^1[3-9]\d{9}$/, message: '请输入有效的中国大陆手机号', trigger: 'blur' },
],
password: [
{ required: true, message: '请设置登录密码', trigger: 'blur' },
{ min: 8, max: 72, message: '密码长度应为 8–72 位', trigger: 'blur' },
],
agreement: [{ validator: (_rule, value, callback) => value ? callback() : callback(new Error('请先阅读并同意服务协议和隐私政策')), trigger: 'change' }],
}
async function submit() {
if (!formRef.value || submitting.value) return
const valid = await formRef.value.validate().catch(() => false)
if (!valid) {
await nextTick()
document.querySelector<HTMLElement>('.auth-form-panel .el-form-item.is-error input')?.focus()
return
}
submitting.value = true
try {
const legalPerson = form.legalPerson.trim()
await registerMerchant({
username: form.username.trim(),
password: form.password,
displayName: form.displayName.trim(),
companyName: form.companyName.trim(),
...(legalPerson ? { legalPerson } : {}),
phone: form.phone.trim(),
contactEmail: form.contactEmail.trim() || undefined,
countryCode: form.countryCode,
address: form.address.trim() || undefined,
})
submittedAt.value = new Intl.DateTimeFormat('zh-CN', {
year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hour12: false,
}).format(new Date())
submitted.value = true
ElMessage.success('企业账号注册成功')
} catch (error) {
ElMessage.error(error instanceof Error ? error.message : '注册失败,请检查信息后重试')
} finally {
submitting.value = false
}
}
</script>
<template>
<AuthShell
variant="register"
switch-text="已有企业账号?"
switch-label="立即登录"
switch-to="/login"
visual-title="加入柏悦,开启高效跨境物流协作"
visual-description="创建企业账号后即可进入客户工作台,维护团队、资料与头程订单。"
:features="['注册成功即可登录', '企业资料独立审核', '审核期间可维护订单草稿']"
>
<div class="auth-form-content auth-form-content--register">
<template v-if="!submitted">
<div class="auth-form-heading">
<h1>企业注册</h1>
<p>填写账号与企业基本信息,注册成功后即可登录。</p>
</div>
<el-form ref="formRef" :model="form" :rules="rules" class="register-form" label-position="top" size="large" @submit.prevent="submit">
<section class="register-section" aria-labelledby="account-section-title">
<h2 id="account-section-title">账号信息</h2>
<div class="register-form-grid">
<el-form-item label="登录用户名" prop="username" required><el-input v-model="form.username" autocomplete="username" maxlength="64" placeholder="以字母开头,支持数字和 _.@-" /></el-form-item>
<el-form-item label="登录密码" prop="password" required><el-input v-model="form.password" type="password" autocomplete="new-password" maxlength="72" show-password placeholder="请设置 8–72 位密码" /></el-form-item>
</div>
</section>
<section class="register-section" aria-labelledby="company-section-title">
<h2 id="company-section-title">企业信息</h2>
<div class="register-form-grid">
<el-form-item label="企业名称" prop="companyName" class="register-form-full" required><el-input v-model="form.companyName" maxlength="100" placeholder="请输入营业执照上的企业名称" /></el-form-item>
<el-form-item label="法定代表人(选填)" prop="legalPerson"><el-input v-model="form.legalPerson" maxlength="64" placeholder="可在企业资料中后续补充" /></el-form-item>
<el-form-item label="国家/地区" prop="countryCode"><el-select v-model="form.countryCode" class="register-select"><el-option label="中国大陆(CN)" value="CN" /></el-select></el-form-item>
</div>
</section>
<section class="register-section" aria-labelledby="contact-section-title">
<h2 id="contact-section-title">联系信息</h2>
<div class="register-form-grid">
<el-form-item label="联系人" prop="displayName" required><el-input v-model="form.displayName" maxlength="64" placeholder="请输入联系人姓名" /></el-form-item>
<el-form-item label="登录手机号" prop="phone" required><el-input v-model="form.phone" type="tel" autocomplete="tel" inputmode="numeric" maxlength="11" placeholder="请输入 11 位手机号" :prefix-icon="Phone" /><span class="register-security-note">注册时同时初始化公司联系电话;注册后两者可分别修改,互不联动。</span></el-form-item>
<el-form-item label="联系邮箱" prop="contactEmail"><el-input v-model="form.contactEmail" type="email" autocomplete="email" maxlength="128" placeholder="选填,用于接收业务通知" :prefix-icon="Mail" /></el-form-item>
<el-form-item label="企业地址" prop="address"><el-input v-model="form.address" maxlength="255" placeholder="选填,最多 255 个字符" /></el-form-item>
</div>
</section>
<el-form-item prop="agreement" class="agreement-item">
<div class="agreement-control">
<el-checkbox v-model="form.agreement"><span class="agreement-required" aria-hidden="true">*</span>我已阅读并同意</el-checkbox>
<span><RouterLink to="/legal/terms" target="_blank" rel="noopener">《用户服务协议》</RouterLink> 和 <RouterLink to="/legal/privacy" target="_blank" rel="noopener">《隐私政策》</RouterLink></span>
</div>
</el-form-item>
<p class="register-security-note">注册成功后账号可立即登录;首次登录需上传营业执照,法人身份证、货代资质证书和银行开户许可证可选填。提交平台审核通过后才能提交订单。</p>
<el-button native-type="submit" class="register-submit" type="success" :loading="submitting">注册企业账号</el-button>
</el-form>
</template>
<section v-else class="registration-result" aria-live="polite">
<CheckCircle2 :size="42" />
<h1>企业账号注册成功</h1>
<p><strong>{{ form.username }}</strong> 现在可以直接登录客户工作台,无需等待注册审核。</p>
<dl><div><dt>企业名称</dt><dd>{{ form.companyName }}</dd></div><div><dt>登录账号</dt><dd>{{ form.username }}</dd></div><div><dt>注册时间</dt><dd>{{ submittedAt }}</dd></div><div><dt>账号状态</dt><dd><el-tag type="success" effect="light">可登录</el-tag></dd></div></dl>
<div class="registration-next-step" role="note"><strong>提交订单前还需完成企业审核</strong><span>登录后请在“企业资料”上传营业执照并提交审核;法人身份证及其他资质可选填。审核期间仍可维护资料、成员和订单草稿。</span></div>
<div class="registration-result-actions"><el-button type="primary" @click="router.push({ path: '/login', query: { account: form.username } })">立即登录</el-button></div>
</section>
</div>
</AuthShell>
</template>