开发了权限分配功能:实现了一个可以在后台勾选页面的功能,通过给角色勾选菜单,就能直接控制不同身份的人登录后能看到哪些页面。 开发了实名认证功能:实现了企业可以提交营业执照认证,个人可以提交身份证件和技能认证的功能,管理员在后台可以进行审核。 开发了任务大厅功能:实现了企业可以发布需要做的任务,个人用户能在任务大厅里看到这些任务,并且可以点击申请接单,大家都能看到任务是“进行中”还是“已完成”状态。 开发了专家库与邀约功能:实现了企业可以去专家库里搜索合适的人才,并且可以直接给他们发送工作邀约。 开发了平台数据大屏展示功能:实现了在首页和各自的工作台页面,展示任务数量、收益金额等核心数据的概览面板。
173 lines
6.3 KiB
Vue
173 lines
6.3 KiB
Vue
<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>
|