Files
jurong_circle_front_app/pages/register/register.vue

518 lines
13 KiB
Vue
Raw Normal View History

2025-09-15 21:03:25 +08:00
<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>
2025-09-15 21:03:25 +08:00
</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
2025-09-16 16:05:34 +08:00
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
2025-09-15 21:03:25 +08:00
}
// 验证码
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 {
// 如果确认密码已输入,重新验证确认密码
2025-09-16 16:05:34 +08:00
// if (userRegister.userRegisterForm.confirmPassword && userRegister.userRegisterForm.confirmPassword == userRegister.userRegisterForm.password) {
// return true
// }
// callback(new Error('两次输入的密码不一致'));
return true
2025-09-15 21:03:25 +08:00
}
};
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: {
2025-09-16 16:05:34 +08:00
username: '',
phone: '',
smsCode: '',
province: '',
city: '',
district: '',
district_id: '',
2025-09-15 21:03:25 +08:00
regionLabel: '',
2025-09-16 16:05:34 +08:00
password: '',
confirmPassword: '',
captcha: '',
2025-09-15 21:03:25 +08:00
},
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'
2025-09-16 16:05:34 +08:00
}],
2025-09-15 21:03:25 +08:00
}
})
// 注册处理
const handleRegister = async () => {
if (!is_read.value) {
uni.showToast({
title: '请先同意协议',
icon: 'none'
})
return
}
2025-09-16 16:05:34 +08:00
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.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);
2025-09-15 21:03:25 +08:00
}
}
// 手机验证码
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 = () => {
// 校验手机号
2025-09-16 16:05:34 +08:00
console.log("发送验证码");
2025-09-15 21:03:25 +08:00
if (msgCodeRef.value.canGetCode) {
2025-09-16 16:05:34 +08:00
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'
})
}
})
2025-09-15 21:03:25 +08:00
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;
2025-09-15 21:03:25 +08:00
letter-spacing: -2%;
text-align: center;
color: #000000;
text-align: left;
white-space: nowrap;
2025-09-15 21:03:25 +08:00
span {
font-family: Work Sans;
font-weight: 400;
font-size: 26rpx;
2025-09-15 21:03:25 +08:00
leading-trim: NONE;
// line-height: 30rpx;
2025-09-15 21:03:25 +08:00
letter-spacing: -2%;
text-align: center;
color: #3781EF;
2025-09-16 16:05:34 +08:00
display: ruby;
2025-09-15 21:03:25 +08:00
}
}
.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>