Files
consumer-front/src/pages/register/register.vue
T
kk 842defea21
Uni-app H5 Deploy (Prod + Staging) / deploy (release) Successful in 44s
注册成功后保存用户id与手机号
2026-07-11 18:30:16 +08:00

398 lines
9.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
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="header">
<view class="title">用户注册</view>
<view class="subtitle">请输入手机号获取验证码完成注册</view>
</view>
<!-- 用户信息展示来自微信授权 -->
<view v-if="authInfo.nickname" class="auth-info">
<image class="auth-avatar" :src="authInfo.avatar || '/static/default-avatar.png'" mode="aspectFill" />
<text class="auth-nickname">{{ authInfo.nickname }}</text>
</view>
<!-- 表单区域 -->
<view class="form-area">
<!-- 手机号 -->
<view class="input-group">
<view class="input-label">手机号</view>
<view class="input-wrapper">
<input
class="input-field"
type="number"
maxlength="11"
placeholder="请输入手机号"
placeholder-class="placeholder"
v-model="phone"
/>
</view>
</view>
<!-- 验证码 -->
<view class="input-group">
<view class="input-label">验证码</view>
<view class="input-wrapper code-wrapper">
<input
class="input-field"
type="number"
maxlength="6"
placeholder="请输入验证码"
placeholder-class="placeholder"
v-model="code"
/>
<view
class="code-btn"
:class="{ disabled: countdown > 0 }"
@click="handleGetCode"
>
{{ countdown > 0 ? countdown + 's' : '获取验证码' }}
</view>
</view>
</view>
<!-- 注册按钮 -->
<view class="submit-btn" :class="{ active: canSubmit }" @click="handleRegister">
注册
</view>
</view>
<!-- 底部协议 -->
<view class="agreement">
<text class="agreement-text">注册表示同意</text>
<text class="agreement-link" @click="showAgreement('user')">用户协议</text>
<text class="agreement-text"></text>
<text class="agreement-link" @click="showAgreement('privacy')">隐私政策</text>
</view>
</view>
</template>
<script>
import { gatewayPost } from '@/utils/request.js';
import config from '@/config/env.js';
export default {
data() {
return {
phone: '',
code: '',
countdown: 0,
timer: null,
tempToken: '',
authInfo: { nickname: '', avatar: '' },
deviceId: '',
};
},
computed: {
canSubmit() {
return this.phone.length === 11 && this.code.length >= 4;
}
},
onLoad(options) {
this.deviceId = options.device_id || '';
// 从缓存读取授权信息(loading 页写入)
this.tempToken = uni.getStorageSync('temp_token') || '';
const cachedAuthInfo = uni.getStorageSync('auth_info');
if (cachedAuthInfo) {
this.authInfo = cachedAuthInfo;
}
// 如果没有 temp_token,提示用户重新授权
if (!this.tempToken) {
uni.showToast({ title: '授权信息已过期,请重新登录', icon: 'none' });
}
},
beforeDestroy() {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
},
methods: {
// 获取验证码
async handleGetCode() {
if (this.countdown > 0) return;
if (!/^1[3-9]\d{9}$/.test(this.phone)) {
uni.showToast({ title: '请输入正确的手机号', icon: 'none' });
return;
}
if (!this.tempToken) {
uni.showToast({ title: '授权信息已过期,请重新登录', icon: 'none' });
return;
}
try {
const res = await gatewayPost('/api/v1/user/sms/send', {
phone: this.phone,
temp_token: this.tempToken,
purpose: 'register',
});
const ret = res.data || {};
if (ret.code === 0) {
uni.showToast({ title: '验证码已发送', icon: 'success' });
this.startCountdown();
} else {
uni.showToast({ title: ret.message || '发送失败', icon: 'none' });
}
} catch (e) {
uni.showToast({ title: '网络请求失败', icon: 'none' });
}
},
startCountdown() {
this.countdown = 60;
this.timer = setInterval(() => {
this.countdown--;
if (this.countdown <= 0) {
clearInterval(this.timer);
this.timer = null;
}
}, 1000);
},
// 注册(Mock 模式也走真实接口)
async handleRegister() {
if (!this.canSubmit) return;
if (!/^1[3-9]\d{9}$/.test(this.phone)) {
uni.showToast({ title: '请输入正确的手机号', icon: 'none' });
return;
}
if (this.code.length < 4) {
uni.showToast({ title: '请输入验证码', icon: 'none' });
return;
}
if (!this.tempToken) {
uni.showToast({ title: '授权信息已过期,请重新登录', icon: 'none' });
return;
}
uni.showLoading({ title: '注册中...' });
try {
const res = await gatewayPost('/api/v1/user/register', {
temp_token: this.tempToken,
phone: this.phone,
code: this.code,
});
const ret = res.data || {};
console.log('[register] 注册响应:', JSON.stringify(ret, null, 2));
if (ret.code === 0 && ret.data) {
// 保存 token
uni.setStorageSync('token', ret.data.token);
// 存储 user_info(接口返回 user_info.user_id 和 phone
const existing = uni.getStorageSync('user_info') || {};
const apiUserInfo = ret.data.user_info || {};
const userInfo = {
user_id: apiUserInfo.user_id || existing.user_id || '',
phone: apiUserInfo.phone || this.phone || existing.phone || '',
nickname: existing.nickname || '',
avatar: existing.avatar || '',
};
// Mock 模式下补充 mock 数据
if (config.mockWechatLogin) {
const mockInfo = config.mockUser.user_info;
userInfo.nickname = userInfo.nickname || mockInfo.nickname;
userInfo.avatar = userInfo.avatar || mockInfo.avatar;
}
uni.setStorageSync('user_info', userInfo);
console.log('[register] 存储 user_info:', userInfo);
// 清除临时数据
uni.removeStorageSync('temp_token');
uni.removeStorageSync('auth_info');
uni.hideLoading();
uni.showToast({ title: '注册成功', icon: 'success' });
setTimeout(() => this.navigateToTarget(), 1500);
} else {
uni.hideLoading();
uni.showToast({ title: ret.message || '注册失败', icon: 'none' });
}
} catch (e) {
uni.hideLoading();
uni.showToast({ title: '网络请求失败', icon: 'none' });
}
},
// 跳转到目标页面
navigateToTarget() {
const scanRedirectUrl = uni.getStorageSync('__scan_redirect_url');
uni.removeStorageSync('__scan_redirect_url');
const url = scanRedirectUrl
? scanRedirectUrl
: this.deviceId
? `/pages/index/index?device_id=${this.deviceId}`
: '/pages/index/index';
uni.redirectTo({ url });
},
showAgreement(type) {
const title = type === 'user' ? '用户协议' : '隐私政策';
uni.showToast({ title: title + '开发中', icon: 'none' });
}
}
};
</script>
<style scoped>
page {
height: 100%;
background-color: #fff;
}
.register-page {
min-height: 100vh;
background-color: #fff;
padding: 0 60rpx;
}
/* 顶部标题 */
.header {
padding-top: 180rpx;
margin-bottom: 40rpx;
}
.title {
font-size: 48rpx;
font-weight: bold;
color: #333;
margin-bottom: 16rpx;
}
.subtitle {
font-size: 28rpx;
color: #999;
}
/* 微信授权信息 */
.auth-info {
display: flex;
align-items: center;
padding: 24rpx 0;
margin-bottom: 40rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.auth-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
margin-right: 20rpx;
background-color: #e0e0e0;
}
.auth-nickname {
font-size: 30rpx;
color: #333;
font-weight: 500;
}
/* 表单区域 */
.form-area {
width: 100%;
}
.input-group {
margin-bottom: 40rpx;
}
.input-label {
font-size: 28rpx;
color: #333;
margin-bottom: 16rpx;
font-weight: 500;
}
.input-wrapper {
display: flex;
align-items: center;
border-bottom: 2rpx solid #e5e5e5;
padding-bottom: 16rpx;
}
.input-field {
flex: 1;
height: 80rpx;
font-size: 32rpx;
color: #333;
}
.placeholder {
color: #ccc;
font-size: 32rpx;
}
/* 验证码输入框 */
.code-wrapper {
position: relative;
}
.code-btn {
flex-shrink: 0;
font-size: 28rpx;
color: #2979ff;
padding: 12rpx 24rpx;
border: 2rpx solid #2979ff;
border-radius: 8rpx;
white-space: nowrap;
}
.code-btn.disabled {
color: #999;
border-color: #e5e5e5;
}
/* 注册按钮 */
.submit-btn {
width: 100%;
height: 96rpx;
background: #e5e5e5;
border-radius: 48rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
color: #fff;
margin-top: 60rpx;
transition: all 0.3s;
}
.submit-btn.active {
background: linear-gradient(135deg, #2979ff, #1e60e0);
box-shadow: 0 8rpx 24rpx rgba(41, 121, 255, 0.4);
}
/* 底部协议 */
.agreement {
margin-top: 80rpx;
padding-bottom: env(safe-area-inset-bottom);
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
}
.agreement-text {
font-size: 24rpx;
color: #999;
}
.agreement-link {
font-size: 24rpx;
color: #2979ff;
}
</style>