Files
opc-web/src/views/RegisterView.vue

173 lines
6.3 KiB
Vue
Raw Normal View History

<script setup lang="ts">
import { ref } from 'vue';
import { Rocket, Plus } from 'lucide-vue-next';
import { useRouter } from 'vue-router';
import { useAuthStore } from '@/stores/auth';
import { ElMessage } from 'element-plus';
import { uploadFileToMinIO } from '@/api';
const router = useRouter();
const authStore = useAuthStore();
const errorMsg = ref('');
const isLoading = ref(false);
const form = ref({
username: '', phone: '', email: '',
nickname: '', password: '', confirmPassword: '',
avatar_url: ''
});
const handleAvatarUpload = async (options: any) => {
try {
const url = await uploadFileToMinIO(options.file, 'avatars');
form.value.avatar_url = url;
ElMessage.success('头像上传成功');
} catch (error) {
ElMessage.error('头像上传失败,请重试');
}
};
const handleRegister = async () => {
if (!form.value.username.trim()) { errorMsg.value = '用户名不能为空'; return; }
if (form.value.password.length < 6) { errorMsg.value = '密码长度至少为 6 位'; return; }
if (form.value.password !== form.value.confirmPassword) { errorMsg.value = '两次输入的密码不一致'; return; }
if (form.value.phone && !/^1[3-9]\d{9}$/.test(form.value.phone)) { errorMsg.value = '请输入有效的11位手机号'; return; }
if (form.value.email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(form.value.email)) { errorMsg.value = '请输入有效的邮箱地址'; return; }
try {
isLoading.value = true;
errorMsg.value = '';
await authStore.register({
username: form.value.username,
phone: form.value.phone || undefined,
email: form.value.email || undefined,
password: form.value.password,
nickname: form.value.nickname || form.value.username,
avatar_url: form.value.avatar_url || undefined
});
await authStore.login({ username: form.value.username, password: form.value.password });
router.push('/user/certification/apply');
} catch (e: any) {
if (e.response?.data) {
const data = e.response.data;
if (typeof data === 'object') {
const errors = Object.entries(data).map(([key, val]) => {
const fn: any = { username: '用户名', phone: '手机号', email: '邮箱', password: '密码', nickname: '昵称' }[key] || key;
return `${fn}: ${Array.isArray(val) ? val[0] : val}`;
});
errorMsg.value = errors.join('; ');
} else {
errorMsg.value = data.detail || '注册失败';
}
} else {
errorMsg.value = '网络错误,请检查后端服务是否运行';
}
} finally {
isLoading.value = false;
}
};
</script>
<template>
<div class="min-h-screen bg-gray-50 flex items-center justify-center px-4 py-12">
<div class="max-w-lg w-full">
<el-card shadow="always" class="!rounded-2xl !p-2">
<div class="text-center mb-6 pt-4">
<div class="mx-auto h-14 w-14 bg-gray-900 rounded-2xl flex items-center justify-center mb-4">
<Rocket class="w-7 h-7 text-blue-400" />
</div>
<h2 class="text-2xl font-bold text-gray-800">加入 <span class="text-blue-600">CorpScale</span></h2>
<p class="text-sm text-gray-400 mt-1">开启您的一人公司智能之旅</p>
</div>
<el-form @submit.prevent="handleRegister" label-position="top">
<el-alert v-if="errorMsg" type="error" :title="errorMsg" :closable="false" class="mb-4" />
<!-- Avatar Upload -->
<div class="flex justify-center mb-6">
<el-upload
action=""
class="avatar-uploader"
:show-file-list="false"
:http-request="handleAvatarUpload"
accept="image/*"
>
<img v-if="form.avatar_url" :src="form.avatar_url" class="w-full h-full object-cover" />
<div v-else class="text-gray-400 flex flex-col items-center">
<Plus class="w-6 h-6 mb-1" />
<span class="text-[10px]">上传头像</span>
</div>
</el-upload>
</div>
<el-form-item label="用户名" required>
<el-input v-model="form.username" placeholder="请输入用户名" size="large" />
</el-form-item>
<el-row :gutter="12">
<el-col :span="12">
<el-form-item label="手机号(可选)">
<el-input v-model="form.phone" placeholder="11位手机号" size="large" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="邮箱(可选)">
<el-input v-model="form.email" type="email" placeholder="email@example.com" size="large" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="显示昵称">
<el-input v-model="form.nickname" placeholder="显示昵称(不填则使用用户名)" size="large" />
</el-form-item>
<el-row :gutter="12">
<el-col :span="12">
<el-form-item label="设置密码" required>
<el-input v-model="form.password" type="password" placeholder="至少6位" size="large" show-password />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="确认密码" required>
<el-input v-model="form.confirmPassword" type="password" placeholder="再次输入" size="large" show-password />
</el-form-item>
</el-col>
</el-row>
<el-button type="primary" native-type="submit" :loading="isLoading" class="w-full" size="large">
{{ isLoading ? '正在处理...' : '立即注册账户' }}
</el-button>
<el-divider>
<span class="text-xs text-gray-400">已有账户</span>
</el-divider>
<el-button class="w-full" @click="router.push('/login')">去登录</el-button>
</el-form>
</el-card>
</div>
</div>
</template>
<style scoped>
.avatar-uploader {
display: flex;
justify-content: center;
}
.avatar-uploader :deep(.el-upload) {
width: 96px;
height: 96px;
border-radius: 50%;
border: 2px dashed #e5e7eb;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
cursor: pointer;
transition: border-color 0.3s;
}
.avatar-uploader :deep(.el-upload:hover) {
border-color: #60a5fa;
}
</style>