This commit is contained in:
张成
2025-12-16 15:55:42 +08:00
parent f3e6413bfe
commit 41e03daa50
7 changed files with 1077 additions and 28 deletions

View File

@@ -0,0 +1,38 @@
/**
* 邀请注册 API 服务
* 封装邀请注册相关的API调用
*/
class InviteRegisterServer {
/**
* 发送短信验证码
* @param {string} phone 手机号
* @returns {Promise}
*/
sendSmsCode(phone) {
return window.framework.http.post('/invite/send-sms', {
phone: phone
});
}
/**
* 邀请注册
* @param {Object} params 注册参数
* @param {string} params.phone 手机号
* @param {string} params.password 密码
* @param {string} params.sms_code 短信验证码
* @param {string} params.invite_code 邀请码
* @returns {Promise}
*/
register(params) {
return window.framework.http.post('/invite/register', {
phone: params.phone,
password: params.password,
sms_code: params.sms_code,
invite_code: params.invite_code
});
}
}
export default new InviteRegisterServer();

View File

@@ -25,6 +25,9 @@ import JobTypes from '@/views/work/job_types.vue'
// 首页模块
import HomeIndex from '@/views/home/index.vue'
// 邀请注册模块
import InviteRegister from '@/views/invite/invite_register.vue'
/**
@@ -53,6 +56,7 @@ const componentMap = {
'system/version': Version,
'work/job_types': JobTypes,
'home/index': HomeIndex,
'invite/invite_register': InviteRegister,
}
export default componentMap

View File

@@ -0,0 +1,359 @@
<template>
<div class="invite-register-page">
<div class="register-container">
<Card class="register-card">
<div slot="title" class="card-title">
<Icon type="ios-person-add" size="24" />
<span>邀请注册</span>
</div>
<div class="register-form">
<!-- 邀请码提示 -->
<Alert v-if="inviteCode" type="success" show-icon style="margin-bottom: 20px;">
<span slot="desc">您正在通过邀请码 <strong>{{ inviteCode }}</strong> 进行注册</span>
</Alert>
<Alert v-else type="warning" show-icon style="margin-bottom: 20px;">
<span slot="desc">未检测到邀请码请通过邀请链接访问</span>
</Alert>
<Form ref="registerForm" :model="formData" :rules="formRules" :label-width="100">
<!-- 手机号 -->
<FormItem label="手机号" prop="phone">
<Input
v-model="formData.phone"
placeholder="请输入手机号"
:maxlength="11"
@on-blur="validatePhone"
>
<Icon type="ios-phone-portrait" slot="prefix" />
</Input>
</FormItem>
<!-- 密码 -->
<FormItem label="密码" prop="password">
<Input
v-model="formData.password"
type="password"
placeholder="请输入密码至少6位"
:maxlength="50"
password
>
<Icon type="ios-lock" slot="prefix" />
</Input>
</FormItem>
<!-- 确认密码 -->
<FormItem label="确认密码" prop="confirmPassword">
<Input
v-model="formData.confirmPassword"
type="password"
placeholder="请再次输入密码"
:maxlength="50"
password
>
<Icon type="ios-lock" slot="prefix" />
</Input>
</FormItem>
<!-- 短信验证码 -->
<FormItem label="短信验证码" prop="sms_code">
<div class="sms-code-wrapper">
<Input
v-model="formData.sms_code"
placeholder="请输入短信验证码"
:maxlength="6"
style="width: 200px;"
>
<Icon type="ios-keypad" slot="prefix" />
</Input>
<Button
:disabled="smsCodeDisabled"
:loading="smsCodeLoading"
@click="handleSendSmsCode"
style="margin-left: 10px;"
>
{{ smsCodeButtonText }}
</Button>
</div>
</FormItem>
<!-- 提交按钮 -->
<FormItem>
<Button
type="primary"
size="large"
:loading="registerLoading"
@click="handleRegister"
style="width: 100%;"
>
注册
</Button>
</FormItem>
</Form>
<!-- 注册说明 -->
<div class="register-tips">
<p><strong>注册说明</strong></p>
<ul>
<li>手机号将作为您的登录账号</li>
<li>密码长度至少6位建议使用字母+数字组合</li>
<li>短信验证码有效期为5分钟</li>
<li>注册成功后邀请人将获得3天试用期奖励</li>
</ul>
</div>
</div>
</Card>
</div>
</div>
</template>
<script>
import inviteRegisterServer from '@/api/invite/invite_register_server.js';
export default {
name: 'InviteRegister',
data() {
// 验证确认密码
const validateConfirmPassword = (rule, value, callback) => {
if (!value) {
callback(new Error('请再次输入密码'));
} else if (value !== this.formData.password) {
callback(new Error('两次输入的密码不一致'));
} else {
callback();
}
};
return {
inviteCode: '', // 邀请码从URL参数获取
formData: {
phone: '',
password: '',
confirmPassword: '',
sms_code: ''
},
formRules: {
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{ pattern: /^1[3-9]\d{9}$/, message: '手机号格式不正确', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, message: '密码长度不能少于6位', trigger: 'blur' }
],
confirmPassword: [
{ required: true, message: '请再次输入密码', trigger: 'blur' },
{ validator: validateConfirmPassword, trigger: 'blur' }
],
sms_code: [
{ required: true, message: '请输入短信验证码', trigger: 'blur' },
{ pattern: /^\d{6}$/, message: '验证码为6位数字', trigger: 'blur' }
]
},
smsCodeLoading: false,
smsCodeDisabled: false,
smsCodeCountdown: 0,
registerLoading: false
};
},
computed: {
smsCodeButtonText() {
if (this.smsCodeCountdown > 0) {
return `${this.smsCodeCountdown}秒后重新获取`;
}
return '获取验证码';
}
},
mounted() {
// 从URL参数获取邀请码
this.getInviteCodeFromUrl();
},
methods: {
/**
* 从URL参数获取邀请码
*/
getInviteCodeFromUrl() {
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
if (code) {
this.inviteCode = code;
} else {
this.$Message.warning('未检测到邀请码,请通过邀请链接访问');
}
},
/**
* 验证手机号
*/
validatePhone() {
this.$refs.registerForm.validateField('phone');
},
/**
* 发送短信验证码
*/
async handleSendSmsCode() {
// 先验证手机号
this.$refs.registerForm.validateField('phone', async (valid) => {
if (!valid) {
return;
}
if (!this.formData.phone) {
this.$Message.error('请先输入手机号');
return;
}
// 验证手机号格式
const phoneRegex = /^1[3-9]\d{9}$/;
if (!phoneRegex.test(this.formData.phone)) {
this.$Message.error('手机号格式不正确');
return;
}
this.smsCodeLoading = true;
try {
const result = await inviteRegisterServer.sendSmsCode(this.formData.phone);
if (result.code === 0) {
this.$Message.success('短信验证码已发送,请注意查收');
// 开始倒计时
this.startCountdown();
} else {
this.$Message.error(result.message || '发送短信验证码失败');
}
} catch (error) {
const errorMessage = error.response?.data?.message || error.message || '发送短信验证码失败';
this.$Message.error(errorMessage);
} finally {
this.smsCodeLoading = false;
}
});
},
/**
* 开始倒计时
*/
startCountdown() {
this.smsCodeCountdown = 60;
this.smsCodeDisabled = true;
const timer = setInterval(() => {
this.smsCodeCountdown--;
if (this.smsCodeCountdown <= 0) {
clearInterval(timer);
this.smsCodeDisabled = false;
}
}, 1000);
},
/**
* 注册
*/
async handleRegister() {
// 验证表单
this.$refs.registerForm.validate(async (valid) => {
if (!valid) {
return;
}
if (!this.inviteCode) {
this.$Message.error('邀请码不能为空,请通过邀请链接访问');
return;
}
this.registerLoading = true;
try {
const result = await inviteRegisterServer.register({
phone: this.formData.phone,
password: this.formData.password,
sms_code: this.formData.sms_code,
invite_code: this.inviteCode
});
if (result.code === 0) {
this.$Message.success('注册成功!');
// 延迟跳转到登录页面或提示用户登录
setTimeout(() => {
this.$Message.info('请使用注册的手机号和密码登录');
// 可以跳转到登录页面
// this.$router.push('/login');
}, 2000);
} else {
this.$Message.error(result.message || '注册失败');
}
} catch (error) {
const errorMessage = error.response?.data?.message || error.message || '注册失败';
this.$Message.error(errorMessage);
} finally {
this.registerLoading = false;
}
});
}
}
};
</script>
<style lang="less" scoped>
.invite-register-page {
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.register-container {
width: 100%;
max-width: 500px;
}
.register-card {
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
border-radius: 8px;
overflow: hidden;
}
.card-title {
display: flex;
align-items: center;
gap: 10px;
font-size: 20px;
font-weight: 600;
color: #2d8cf0;
}
.register-form {
padding: 20px 0;
}
.sms-code-wrapper {
display: flex;
align-items: center;
}
.register-tips {
margin-top: 30px;
padding: 15px;
background: #f8f8f9;
border-radius: 4px;
border-left: 4px solid #2d8cf0;
p {
margin: 0 0 10px 0;
font-weight: 600;
color: #515a6e;
}
ul {
margin: 0;
padding-left: 20px;
color: #808695;
li {
margin-bottom: 5px;
line-height: 1.6;
}
}
}
</style>