490 lines
12 KiB
Vue
490 lines
12 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" :label-disabled="true">
|
|||
|
|
我已阅读并同意<span @click="showFile1=true">《用户协议》</span>和<span @click="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) => {
|
|||
|
|
console.log(e);
|
|||
|
|
userRegister.userRegisterForm.regionLabel = e[0].label + "/" + e[1].label + "/" + e[2].label
|
|||
|
|
userRegister.userRegisterForm.region = 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) {
|
|||
|
|
userRegisterRef.value?.validateField('confirmPassword');
|
|||
|
|
}
|
|||
|
|
callback();
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
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: '13758452159',
|
|||
|
|
phone: '13758452159',
|
|||
|
|
smsCode: 'asrfdv',
|
|||
|
|
region: '',
|
|||
|
|
regionLabel: '',
|
|||
|
|
password: 's123456s',
|
|||
|
|
confirmPassword: 's123456s',
|
|||
|
|
captcha: 'vfjs',
|
|||
|
|
},
|
|||
|
|
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
|
|||
|
|
}
|
|||
|
|
// 等待表单验证完成
|
|||
|
|
const valid = await userRegisterRef.value.validate();
|
|||
|
|
if (valid) {
|
|||
|
|
console.log(valid);
|
|||
|
|
}
|
|||
|
|
// userRegisterRef.value.validate((valid : any) => {
|
|||
|
|
// if (valid) {
|
|||
|
|
// // 验证验证码
|
|||
|
|
// captchaAPI.verify({
|
|||
|
|
// captchaId: captchaId.value,
|
|||
|
|
// captchaText: userRegister.userRegisterForm.captcha
|
|||
|
|
// }).then(verifyResponse => {
|
|||
|
|
// console.log(verifyResponse);
|
|||
|
|
// if (!verifyResponse.data.success) {
|
|||
|
|
// uni.showToast({
|
|||
|
|
// title: verifyResponse.data.message || '验证码错误',
|
|||
|
|
// icon: 'error'
|
|||
|
|
// })
|
|||
|
|
// // 重新加载验证码
|
|||
|
|
// loadCaptcha()
|
|||
|
|
// return
|
|||
|
|
// }
|
|||
|
|
// })
|
|||
|
|
// const registerData = {
|
|||
|
|
// username: userRegister.userRegisterForm.phone,
|
|||
|
|
// phone: userRegister.userRegisterForm.phone,
|
|||
|
|
// city: userRegister.userRegisterForm.region,
|
|||
|
|
// password: userRegister.userRegisterForm.password,
|
|||
|
|
// smsCode: userRegister.userRegisterForm.smsCode,
|
|||
|
|
// captchaId: captchaId.value,
|
|||
|
|
// captchaText: userRegister.userRegisterForm.captcha,
|
|||
|
|
// province: userRegister.userRegisterForm.region,
|
|||
|
|
// }
|
|||
|
|
// authAPI.register(registerData).then(response => {
|
|||
|
|
// // 直接注册成功的情况
|
|||
|
|
// // setToken(response.data.token)
|
|||
|
|
// // setUser(response.data.user)
|
|||
|
|
// console.log(response);
|
|||
|
|
// })
|
|||
|
|
// }
|
|||
|
|
// })
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 手机验证码
|
|||
|
|
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 = () => {
|
|||
|
|
// 校验手机号
|
|||
|
|
if (msgCodeRef.value.canGetCode) {
|
|||
|
|
console.log("发送验证码");
|
|||
|
|
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: 100%;
|
|||
|
|
letter-spacing: -2%;
|
|||
|
|
text-align: center;
|
|||
|
|
color: #000000;
|
|||
|
|
text-align: left;
|
|||
|
|
|
|||
|
|
span {
|
|||
|
|
font-family: Work Sans;
|
|||
|
|
font-weight: 400;
|
|||
|
|
font-size: 26rpxpx;
|
|||
|
|
leading-trim: NONE;
|
|||
|
|
line-height: 100%;
|
|||
|
|
letter-spacing: -2%;
|
|||
|
|
text-align: center;
|
|||
|
|
color: #3781EF;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.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>
|