Files
integral-shop/single_uniapp22miao/pages/sub-pages/login/register.vue
panchengyong 786bf78282 更新项目配置和添加小程序模块
- 修改 ArticleController.java
- 更新 application.yml 配置
- 更新 frontend/.env.production 环境配置
- 添加 single_uniapp22miao 小程序模块
- 添加 logs 目录
2026-03-13 13:27:13 +08:00

424 lines
9.5 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="register-page">
<view class="container">
<view class="title">创建您的账号</view>
<view class="subtitle">已有账号<text class="link" @click="goToLogin">立即登录</text></view>
<!-- 注册表单 -->
<view class="form-container">
<!-- 手机号 -->
<view class="form-item">
<view class="form-label">
<text class="icon">📱</text>
<text>手机号</text>
</view>
<input
v-model="formData.mobile"
type="number"
maxlength="11"
placeholder="请输入您的手机号"
class="form-input"
/>
</view>
<!-- 验证码 -->
<view class="form-item">
<view class="form-label">
<text class="icon"></text>
<text>验证码</text>
</view>
<view class="code-input-wrapper">
<input
v-model="formData.code"
type="number"
maxlength="6"
placeholder="请输入验证码"
class="form-input"
/>
<button
class="send-code-btn"
:class="{ 'disabled': countdown > 0 }"
:disabled="countdown > 0 || !canSendCode"
@click="sendCode"
>
{{ countdown > 0 ? `${countdown}s` : '获取验证码' }}
</button>
</view>
</view>
<!-- 密码 -->
<view class="form-item">
<view class="form-label">
<text class="icon">🔒</text>
<text>登录密码</text>
</view>
<input
v-model="formData.password"
:password="!showPassword"
placeholder="请输入登录密码(必填)"
class="form-input"
/>
<view class="eye-icon" @click="togglePassword">
<text>{{ showPassword ? '👁️' : '👁️‍🗨️' }}</text>
</view>
</view>
<!-- 邀请码 -->
<view class="form-item">
<view class="form-label">
<text class="icon">🎁</text>
<text>邀请码选填</text>
</view>
<input
v-model="formData.inviteCode"
placeholder="请输入邀请码"
class="form-input"
/>
</view>
<!-- 同意协议 -->
<view class="agreement">
<checkbox-group @change="onAgreeChange">
<label class="checkbox-label">
<checkbox value="agree" :checked="agreed" color="#FF4757" />
<text>同意</text>
<text class="link" @click.stop="viewAgreement('user')">用户协议</text>
<text></text>
<text class="link" @click.stop="viewAgreement('privacy')">购买委托代卖协议</text>
</label>
</checkbox-group>
</view>
<!-- 注册按钮 -->
<button
class="register-btn"
:class="{ 'disabled': !canRegister }"
:disabled="!canRegister"
:loading="registering"
@click="handleRegister"
>
注册
</button>
</view>
</view>
</view>
</template>
<script>
import { userRegister, sendSms } from '@/api/miao.js';
export default {
data() {
return {
formData: {
mobile: '',
code: '',
password: '',
inviteCode: ''
},
showPassword: false,
agreed: false,
countdown: 0,
registering: false,
timer: null
}
},
computed: {
canSendCode() {
return this.formData.mobile.length === 11;
},
canRegister() {
return this.formData.mobile.length === 11 &&
this.formData.code.length === 6 &&
this.formData.password.length >= 6 &&
this.agreed;
}
},
onUnload() {
if (this.timer) {
clearInterval(this.timer);
}
},
methods: {
// 切换密码显示
togglePassword() {
this.showPassword = !this.showPassword;
},
// 验证手机号
validateMobile(mobile) {
const reg = /^1[3-9]\d{9}$/;
return reg.test(mobile);
},
// 发送验证码
async sendCode() {
if (!this.validateMobile(this.formData.mobile)) {
uni.showToast({
title: '请输入正确的手机号',
icon: 'none'
});
return;
}
try {
const res = await sendSms({
mobile: this.formData.mobile,
event: 'register'
});
if (res.code === 0) {
uni.showToast({
title: '验证码已发送',
icon: 'success'
});
// 开始倒计时
this.countdown = 60;
this.timer = setInterval(() => {
this.countdown--;
if (this.countdown <= 0) {
clearInterval(this.timer);
}
}, 1000);
} else {
uni.showToast({
title: res.msg || '发送失败',
icon: 'none'
});
}
} catch (error) {
console.error('发送验证码失败:', error);
uni.showToast({
title: error.msg || '发送失败',
icon: 'none'
});
}
},
// 同意协议变化
onAgreeChange(e) {
this.agreed = e.detail.value.length > 0;
},
// 查看协议
viewAgreement(type) {
uni.navigateTo({
url: `/pages/sub-pages/agreement/index?type=${type}`
});
},
// 注册
async handleRegister() {
if (!this.validateMobile(this.formData.mobile)) {
uni.showToast({
title: '请输入正确的手机号',
icon: 'none'
});
return;
}
if (this.formData.password.length < 6) {
uni.showToast({
title: '密码长度不能少于6位',
icon: 'none'
});
return;
}
if (!this.agreed) {
uni.showToast({
title: '请先同意用户协议',
icon: 'none'
});
return;
}
this.registering = true;
try {
const res = await userRegister({
mobile: this.formData.mobile,
code: this.formData.code,
password: this.formData.password,
invite_code: this.formData.inviteCode
});
if (res.code === 0) {
uni.showToast({
title: '注册成功',
icon: 'success'
});
// 保存token
if (res.data.token) {
uni.setStorageSync('token', res.data.token);
uni.setStorageSync('userInfo', res.data.user_info);
}
// 跳转到首页或登录页
setTimeout(() => {
uni.switchTab({
url: '/pages/index/index'
});
}, 1500);
} else {
uni.showToast({
title: res.msg || '注册失败',
icon: 'none'
});
}
} catch (error) {
console.error('注册失败:', error);
uni.showToast({
title: error.msg || '注册失败,请重试',
icon: 'none'
});
} finally {
this.registering = false;
}
},
// 去登录页
goToLogin() {
uni.navigateBack();
}
}
}
</script>
<style lang="scss" scoped>
.register-page {
min-height: 100vh;
background-color: #f5f5f5;
}
.container {
padding: 40rpx 30rpx;
.title {
font-size: 48rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
}
.subtitle {
font-size: 26rpx;
color: #666;
margin-bottom: 60rpx;
.link {
color: #FF4757;
}
}
}
.form-container {
background-color: #fff;
border-radius: 20rpx;
padding: 40rpx 30rpx;
.form-item {
margin-bottom: 40rpx;
.form-label {
display: flex;
align-items: center;
margin-bottom: 15rpx;
.icon {
font-size: 28rpx;
margin-right: 10rpx;
}
text {
font-size: 28rpx;
color: #333;
}
}
.form-input {
height: 80rpx;
padding: 0 20rpx;
background-color: #f5f5f5;
border-radius: 40rpx;
font-size: 28rpx;
}
.code-input-wrapper {
display: flex;
align-items: center;
.form-input {
flex: 1;
margin-right: 15rpx;
}
.send-code-btn {
width: 180rpx;
height: 80rpx;
line-height: 80rpx;
background-color: #FF4757;
color: #fff;
border-radius: 40rpx;
font-size: 24rpx;
border: none;
&.disabled {
background-color: #ccc;
}
}
}
.eye-icon {
position: absolute;
right: 30rpx;
top: 50%;
transform: translateY(-50%);
font-size: 32rpx;
}
}
.agreement {
margin-bottom: 40rpx;
.checkbox-label {
display: flex;
align-items: center;
font-size: 24rpx;
color: #666;
checkbox {
margin-right: 10rpx;
}
.link {
color: #FF4757;
}
}
}
.register-btn {
width: 100%;
height: 90rpx;
line-height: 90rpx;
background: linear-gradient(90deg, #FF6B6B, #FF4757);
color: #fff;
border-radius: 45rpx;
font-size: 32rpx;
font-weight: bold;
border: none;
&.disabled {
opacity: 0.6;
}
}
}
</style>