519 lines
13 KiB
Vue
519 lines
13 KiB
Vue
<template>
|
||
<view class="register-container">
|
||
<view class="register-title">
|
||
<view class="title">
|
||
用户注册
|
||
</view>
|
||
<view class="sub-title">
|
||
创建你的账号,欢迎来到炬融圈
|
||
</view>
|
||
</view>
|
||
|
||
<view class="register-main">
|
||
<u-form :model="userRegister.userRegisterForm" class="register-form" ref="userRegisterRef"
|
||
:border-bottom="false" :error-type="['message']" label-width="0">
|
||
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/icon/Phone.png" prop="phone">
|
||
<u-input v-model="userRegister.userRegisterForm.phone" placeholder="请输入手机号" maxlength="11"
|
||
type="number" placeholder-style="color: #737373;" />
|
||
</u-form-item>
|
||
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/icon/Mail.png" prop="smsCode">
|
||
<u-input v-model="userRegister.userRegisterForm.smsCode" placeholder="请输入短信验证码" maxlength="6"
|
||
type="number" placeholder-style="color: #737373;" />
|
||
<template v-slot:right>
|
||
<u-verification-code ref="msgCodeRef" @change="codeMsgChange"></u-verification-code>
|
||
<u-button :disabled="!canSendSMS" size="mini" type="primary"
|
||
@tap="getMsgCode">{{msgCodeBtn}}</u-button>
|
||
</template>
|
||
</u-form-item>
|
||
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/icon/Map pin.png" prop="regionLabel">
|
||
<u-input type="select" v-model="userRegister.userRegisterForm.regionLabel" placeholder="请选择省市区"
|
||
placeholder-style="color: #737373;" @click="showRegitionPicker = true" />
|
||
</u-form-item>
|
||
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/icon/Lock.png" prop="password">
|
||
<u-input type="password" v-model="userRegister.userRegisterForm.password" placeholder="请输入密码"
|
||
maxlength="20" placeholder-style="color: #737373;" />
|
||
</u-form-item>
|
||
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/icon/Lock.png" prop="confirmPassword">
|
||
<u-input type="password" v-model="userRegister.userRegisterForm.confirmPassword" maxlength="20"
|
||
placeholder="请输入确认密码" placeholder-style="color: #737373;" />
|
||
</u-form-item>
|
||
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/icon/Globe.png" prop="captcha">
|
||
<u-input v-model="userRegister.userRegisterForm.captcha" placeholder="请输入验证码" maxlength="4"
|
||
placeholder-style="color: #737373;" />
|
||
<template v-slot:right>
|
||
<image @click="loadCaptcha" class="captcha-img" :src="captcha" mode=""></image>
|
||
</template>
|
||
</u-form-item>
|
||
</u-form>
|
||
|
||
<view class="reflash" @click="loadCaptcha">
|
||
<image class="reflash-icon" src="/static/icon/Repeat.png" mode=""></image>
|
||
刷新验证码
|
||
</view>
|
||
<u-checkbox v-model="is_read" size="26" class="must-read">
|
||
我已阅读并同意
|
||
<span @click.stop="showFile1=true">《用户协议》</span>和<span @click.stop="showFile2=true">《隐私政策》</span>
|
||
</u-checkbox>
|
||
<u-button type="primary" class="register-btn" @click="handleRegister">立即注册</u-button>
|
||
|
||
<view class="login">
|
||
<view class="login-text">没有账号?</view>
|
||
<view class="login-link" @click="handleLogin">立即登录</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 省市区 -->
|
||
<u-select v-model="showRegitionPicker" :list="regionOptions" mode="mutil-column-auto" label-name="label"
|
||
value-name="code" child-name="children" @confirm="handleRegion"></u-select>
|
||
<!-- 协议1 -->
|
||
<u-popup v-model="showFile1" mode="bottom" border-radius="14" :closeable="true">
|
||
<view class="file">
|
||
<h3>用户协议</h3>
|
||
<p>1. 用户应当遵守法律法规,不得发布违法违规内容。</p>
|
||
<p>2. 用户对自己发布的内容承担全部责任。</p>
|
||
<p>3. 平台有权对违规内容进行删除或限制。</p>
|
||
<p>4. 用户应当保护好自己的账号安全。</p>
|
||
<p>5. 平台保留修改本协议的权利。</p>
|
||
</view>
|
||
</u-popup>
|
||
<!-- 协议2 -->
|
||
<u-popup v-model="showFile2" mode="bottom" border-radius="14" :closeable="true">
|
||
<view class="file">
|
||
<h3>隐私政策</h3>
|
||
<p>1. 我们重视用户隐私保护。</p>
|
||
<p>2. 我们只收集必要的用户信息。</p>
|
||
<p>3. 用户信息仅用于提供服务。</p>
|
||
<p>4. 我们不会向第三方泄露用户信息。</p>
|
||
<p>5. 用户有权查看、修改或删除个人信息。</p>
|
||
</view>
|
||
</u-popup>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import {
|
||
onMounted,
|
||
reactive,
|
||
ref,
|
||
computed
|
||
} from 'vue';
|
||
import {
|
||
onReady
|
||
} from '@dcloudio/uni-app';
|
||
import {
|
||
captchaAPI
|
||
} from '../../api/captcha.js';
|
||
import {
|
||
commonAPI
|
||
} from '../../api/common.js';
|
||
import {
|
||
authAPI
|
||
} from '../../api/auth.js';
|
||
|
||
|
||
// 输入框图标样式
|
||
const inputIcon = {
|
||
width: '32rpx',
|
||
verticalAlign: 'middle'
|
||
}
|
||
|
||
// 省市区
|
||
const showRegitionPicker = ref(false)
|
||
const regionOptions = ref()
|
||
|
||
// 加载省市区
|
||
const loadRegion = () => {
|
||
commonAPI.getRegion().then(res => {
|
||
if (res.success) {
|
||
regionOptions.value = res.data
|
||
}
|
||
})
|
||
}
|
||
|
||
// 选择省市区
|
||
const handleRegion = (e) => {
|
||
userRegister.userRegisterForm.regionLabel = e[0].label + "/" + e[1].label + "/" + e[2].label
|
||
userRegister.userRegisterForm.province = e[0].value
|
||
userRegister.userRegisterForm.city = e[1].value
|
||
userRegister.userRegisterForm.district = e[2].value
|
||
userRegister.userRegisterForm.district_id = e[2].value
|
||
}
|
||
|
||
|
||
// 验证码
|
||
const captcha = ref()
|
||
const captchaId = ref()
|
||
|
||
// 请求验证码
|
||
const loadCaptcha = () => {
|
||
captchaAPI.generate().then(res => {
|
||
captcha.value = res.data.image
|
||
captchaId.value = res.data.captchaId
|
||
})
|
||
}
|
||
|
||
|
||
// 校验规则
|
||
const validatePassword = (rule, value, callback) => {
|
||
if (!value) {
|
||
callback(new Error('请输入密码'));
|
||
} else if (value.length < 6) {
|
||
callback(new Error('密码至少6个字符'));
|
||
} else if (value.length > 20) {
|
||
callback(new Error('密码不能超过20个字符'));
|
||
} else if (!/(?=.*[a-zA-Z])(?=.*\d)/.test(value)) {
|
||
callback(new Error('密码必须包含字母和数字'));
|
||
} else {
|
||
// 如果确认密码已输入,重新验证确认密码
|
||
// if (userRegister.userRegisterForm.confirmPassword && userRegister.userRegisterForm.confirmPassword == userRegister.userRegisterForm.password) {
|
||
// return true
|
||
// }
|
||
// callback(new Error('两次输入的密码不一致'));
|
||
return true
|
||
}
|
||
};
|
||
|
||
const validateConfirmPassword = (rule, value, callback) => {
|
||
if (!value) {
|
||
callback(new Error('请确认密码'));
|
||
} else if (value !== userRegister.userRegisterForm.password) {
|
||
callback(new Error('两次输入的密码不一致'));
|
||
} else {
|
||
callback();
|
||
}
|
||
};
|
||
|
||
// 注册表单
|
||
const userRegisterRef = ref()
|
||
const userRegister = reactive({
|
||
userRegisterForm: {
|
||
username: '',
|
||
phone: '',
|
||
smsCode: '',
|
||
province: '',
|
||
city: '',
|
||
district: '',
|
||
district_id: '',
|
||
regionLabel: '',
|
||
password: '',
|
||
confirmPassword: '',
|
||
captcha: '',
|
||
},
|
||
rules: {
|
||
phone: [{
|
||
required: true,
|
||
message: '请输入手机号',
|
||
trigger: ['blur']
|
||
},
|
||
{
|
||
pattern: /^1[3-9]\d{9}$/,
|
||
message: '请输入正确的手机号格式',
|
||
trigger: ['blur']
|
||
}
|
||
],
|
||
smsCode: [{
|
||
required: true,
|
||
message: '请输入短信验证码',
|
||
trigger: ['blur']
|
||
},
|
||
{
|
||
pattern: /^\d{6}$/,
|
||
message: '短信验证码为6位数字',
|
||
trigger: ['blur']
|
||
},
|
||
],
|
||
regionLabel: [{
|
||
required: true,
|
||
message: '请选择省市区',
|
||
trigger: ['change']
|
||
}],
|
||
password: [{
|
||
validator: validatePassword,
|
||
trigger: ['blur']
|
||
}],
|
||
confirmPassword: [{
|
||
validator: validateConfirmPassword,
|
||
trigger: ['blur']
|
||
}],
|
||
captcha: [{
|
||
required: true,
|
||
message: '请输入验证码',
|
||
trigger: ['blur']
|
||
},
|
||
{
|
||
min: 4,
|
||
max: 4,
|
||
message: '验证码长度为4位',
|
||
trigger: 'blur'
|
||
}],
|
||
}
|
||
})
|
||
|
||
// 注册处理
|
||
const handleRegister = async () => {
|
||
if (!is_read.value) {
|
||
uni.showToast({
|
||
title: '请先同意协议',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
try {
|
||
userRegisterRef.value.validate((valid : any) => {
|
||
if (valid) {
|
||
// 验证通过后执行的逻辑
|
||
console.log('表单验证通过', userRegister.userRegisterForm);
|
||
|
||
// 提交注册
|
||
const registerData = {
|
||
username: userRegister.userRegisterForm.phone,
|
||
phone: userRegister.userRegisterForm.phone,
|
||
province: userRegister.userRegisterForm.province,
|
||
city: userRegister.userRegisterForm.city,
|
||
district: userRegister.userRegisterForm.district,
|
||
district_id: userRegister.userRegisterForm.district_id,
|
||
password: userRegister.userRegisterForm.password,
|
||
smsCode: userRegister.userRegisterForm.smsCode,
|
||
captchaId: captchaId.value,
|
||
captchaText: userRegister.userRegisterForm.captcha,
|
||
}
|
||
authAPI.register(registerData).then(response => {
|
||
if (response.success) {
|
||
console.log('注册结果', response);
|
||
uni.clearStorageSync()
|
||
uni.setStorageSync("token", response.token)
|
||
uni.setStorageSync("user", response.user)
|
||
uni.showToast({
|
||
title: '注册成功',
|
||
success() {
|
||
setTimeout(() => {
|
||
uni.switchTab({
|
||
url: '/pages/home/index'
|
||
})
|
||
}, 1000)
|
||
}
|
||
})
|
||
}
|
||
}).catch((err) => {
|
||
setTimeout(() => {
|
||
userRegister.userRegisterForm.captcha = ''
|
||
loadCaptcha()
|
||
}, 1000)
|
||
})
|
||
}
|
||
});
|
||
} catch (error) {
|
||
// 验证失败时会进入这里,无需额外处理(表单会自动显示错误信息)
|
||
console.log('表单验证失败', error);
|
||
}
|
||
}
|
||
|
||
// 手机验证码
|
||
const msgCodeBtn = ref()
|
||
const msgCodeRef = ref()
|
||
|
||
|
||
// 手机验证码变化
|
||
const codeMsgChange = (text) => {
|
||
msgCodeBtn.value = text;
|
||
}
|
||
|
||
// 是否能够发送手机验证码
|
||
const canSendSMS = computed(() => {
|
||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||
return phoneRegex.test(userRegister.userRegisterForm.phone);
|
||
});
|
||
|
||
// 获取手机验证码
|
||
const getMsgCode = () => {
|
||
// 校验手机号
|
||
console.log("发送验证码");
|
||
if (msgCodeRef.value.canGetCode) {
|
||
captchaAPI.smsSend(userRegister.userRegisterForm.phone).then(res => {
|
||
const result = res.json();
|
||
if (result.success) {
|
||
uni.showToast({
|
||
title: '验证码发送成功,请查收短信',
|
||
icon: 'success'
|
||
})
|
||
} else {
|
||
uni.showToast({
|
||
title: result.message || '发送失败,请重试',
|
||
icon: 'error'
|
||
})
|
||
}
|
||
})
|
||
msgCodeRef.value.start();
|
||
} else {
|
||
uni.showToast({
|
||
title: '等待...'
|
||
})
|
||
}
|
||
}
|
||
|
||
// 是否阅读
|
||
const is_read = ref(false)
|
||
const showFile1 = ref(false)
|
||
const showFile2 = ref(false)
|
||
|
||
// 跳转登录页面
|
||
const handleLogin = () => {
|
||
uni.redirectTo({
|
||
url: '/pages/login/login'
|
||
})
|
||
}
|
||
|
||
onMounted(() => {
|
||
loadCaptcha()
|
||
loadRegion()
|
||
})
|
||
|
||
onReady(() => {
|
||
userRegisterRef.value.setRules(userRegister.rules)
|
||
})
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.register-container {
|
||
width: 100%;
|
||
height: 100vh;
|
||
background: linear-gradient(180deg, #BAC9FF 0%, #FFFFFF 100%);
|
||
|
||
.register-title {
|
||
padding-top: 114rpx;
|
||
|
||
.title {
|
||
font-family: SF Pro;
|
||
font-weight: 650;
|
||
font-style: Expanded Semibold;
|
||
font-size: 48rpx;
|
||
leading-trim: NONE;
|
||
line-height: 80rpx;
|
||
letter-spacing: 0%;
|
||
text-align: center;
|
||
color: #000000;
|
||
}
|
||
|
||
.sub-title {
|
||
font-family: Work Sans;
|
||
font-weight: 400;
|
||
font-size: 26rpx;
|
||
leading-trim: NONE;
|
||
line-height: 100%;
|
||
letter-spacing: -2%;
|
||
text-align: center;
|
||
color: #5B5B5B;
|
||
}
|
||
}
|
||
|
||
.register-main {
|
||
|
||
.register-form {
|
||
padding: 20rpx 98rpx 10rpx;
|
||
}
|
||
|
||
.captcha-img {
|
||
width: 200rpx;
|
||
height: 80rpx;
|
||
}
|
||
|
||
.reflash {
|
||
width: 90%;
|
||
margin-bottom: 30rpx;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
align-items: center;
|
||
|
||
|
||
// 文字
|
||
font-family: Work Sans;
|
||
font-weight: 400;
|
||
font-size: 26rpx;
|
||
leading-trim: NONE;
|
||
line-height: 100%;
|
||
letter-spacing: -2%;
|
||
color: #3781EF;
|
||
|
||
.reflash-icon {
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
margin-right: 10rpx;
|
||
}
|
||
}
|
||
|
||
.must-read {
|
||
padding: 0 76rpx;
|
||
font-family: Work Sans;
|
||
font-weight: 400;
|
||
leading-trim: NONE;
|
||
// line-height: 30rpx;
|
||
letter-spacing: -2%;
|
||
text-align: center;
|
||
color: #000000;
|
||
text-align: left;
|
||
white-space: nowrap;
|
||
|
||
span {
|
||
font-family: Work Sans;
|
||
font-weight: 400;
|
||
font-size: 26rpx;
|
||
leading-trim: NONE;
|
||
// line-height: 30rpx;
|
||
letter-spacing: -2%;
|
||
text-align: center;
|
||
color: #3781EF;
|
||
display: ruby;
|
||
}
|
||
}
|
||
|
||
.register-btn {
|
||
margin: 40rpx 54rpx 20rpx;
|
||
font-family: SF Pro;
|
||
font-weight: 650;
|
||
font-style: Expanded Semibold;
|
||
font-size: 40rpx;
|
||
leading-trim: NONE;
|
||
line-height: 46rpx;
|
||
letter-spacing: 0%;
|
||
text-align: center;
|
||
}
|
||
|
||
|
||
.login {
|
||
margin: 40rpx 0 80rpx;
|
||
padding-bottom: 80rpx;
|
||
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
|
||
// 文字
|
||
font-family: Work Sans;
|
||
font-weight: 400;
|
||
font-size: 26rpx;
|
||
leading-trim: NONE;
|
||
line-height: 100%;
|
||
letter-spacing: -2%;
|
||
text-align: center;
|
||
|
||
|
||
.login-text {
|
||
color: #737373;
|
||
}
|
||
|
||
.login-link {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
color: #3781EF;
|
||
}
|
||
}
|
||
}
|
||
|
||
.file {
|
||
padding: 80rpx 40rpx;
|
||
}
|
||
|
||
}
|
||
</style> |