340 lines
7.8 KiB
Vue
340 lines
7.8 KiB
Vue
<template>
|
||
<view class="register-page">
|
||
<view class="header">
|
||
<text class="header-title">注册信息</text>
|
||
<text class="header-desc">填写资料即可参与答题抽奖</text>
|
||
</view>
|
||
<view class="form">
|
||
<view class="field">
|
||
<text class="label">姓名</text>
|
||
<view class="input-wrap">
|
||
<text class="input-icon">👤</text>
|
||
<input class="input" v-model="userName" placeholder="请输入您的姓名" />
|
||
</view>
|
||
<text class="name-tip">本次演唱会门票实行实名制管理,参与抽奖活动须如实填报本人姓名与手机号码;中奖后须在24小时内完成兑奖操作,兑奖时需补充填报本人身份证号码。</text>
|
||
</view>
|
||
<view class="field">
|
||
<text class="label">手机号</text>
|
||
<view class="input-wrap">
|
||
<text class="input-icon">📱</text>
|
||
<input class="input" v-model="phone" placeholder="请输入手机号" type="number" maxlength="11" />
|
||
</view>
|
||
</view>
|
||
<view class="field">
|
||
<text class="label">验证码</text>
|
||
<view class="field-row">
|
||
<view class="input-wrap code-input-wrap">
|
||
<text class="input-icon">✉️</text>
|
||
<input class="input" v-model="smsCode" placeholder="请输入验证码" type="number" maxlength="6" />
|
||
</view>
|
||
<button class="code-btn" @tap="sendCode" :disabled="sending" :class="{ disabled: sending }">
|
||
{{ sending ? countdown + 's' : '获取验证码' }}
|
||
</button>
|
||
</view>
|
||
</view>
|
||
<view class="agree-row" @tap="agreed = !agreed">
|
||
<view class="agree-checkbox" :class="{ checked: agreed }">
|
||
<text v-if="agreed" class="agree-check-mark">✓</text>
|
||
</view>
|
||
<view class="agree-text">
|
||
<text>我已阅读并同意</text>
|
||
<text class="agree-link" @tap.stop="goPrivacy">《用户隐私协议》</text>
|
||
</view>
|
||
</view>
|
||
<button class="submit-btn" @tap="register" :disabled="submitting" :class="{ disabled: submitting }">
|
||
{{ submitting ? '提交中...' : '立即注册' }}
|
||
</button>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
data() {
|
||
return {
|
||
userName: '',
|
||
phone: '',
|
||
smsCode: '',
|
||
sending: false,
|
||
countdown: 60,
|
||
timer: null,
|
||
submitting: false,
|
||
agreed: false
|
||
}
|
||
},
|
||
methods: {
|
||
goPrivacy() {
|
||
uni.navigateTo({ url: '/pages/privacy/privacy' })
|
||
},
|
||
sendCode() {
|
||
if (!/^1\d{10}$/.test(this.phone)) {
|
||
uni.showToast({ title: '请输入正确手机号', icon: 'none' })
|
||
return
|
||
}
|
||
this.sending = true
|
||
this.$u.api.sendSms(this.phone).then(res => {
|
||
if (res.code === 0) {
|
||
uni.showToast({ title: '验证码已发送', icon: 'none' })
|
||
this.startCountdown()
|
||
} else {
|
||
uni.showToast({ title: res.msg || '发送失败', icon: 'none' })
|
||
this.sending = false
|
||
}
|
||
}).catch(() => {
|
||
uni.showToast({ title: '网络错误', icon: 'none' })
|
||
this.sending = false
|
||
})
|
||
},
|
||
startCountdown() {
|
||
this.countdown = 60
|
||
this.timer = setInterval(() => {
|
||
this.countdown--
|
||
if (this.countdown <= 0) {
|
||
clearInterval(this.timer)
|
||
this.timer = null
|
||
this.sending = false
|
||
}
|
||
}, 1000)
|
||
},
|
||
register() {
|
||
if (!this.userName || !this.phone || !this.smsCode) {
|
||
uni.showToast({ title: '请填写完整信息', icon: 'none' })
|
||
return
|
||
}
|
||
if (!this.agreed) {
|
||
uni.showToast({ title: '请阅读并同意《用户隐私协议》', icon: 'none' })
|
||
return
|
||
}
|
||
this.submitting = true
|
||
const openId = uni.getStorageSync('openId')
|
||
this.$u.api.userRegist({
|
||
wenjuan_id: 1001,
|
||
open_id: openId,
|
||
user_name: this.userName,
|
||
user_phone: this.phone,
|
||
sms_code: this.smsCode,
|
||
channel: 1
|
||
}).then(res => {
|
||
if (res.code === 0) {
|
||
uni.setStorageSync('isRegistered', true)
|
||
const data = res.Data || {}
|
||
const userId = data.user_id || data.uesr_id
|
||
if (userId) uni.setStorageSync('userId', userId)
|
||
if (data.user_name) uni.setStorageSync('userName', data.user_name)
|
||
if (data.user_phone) uni.setStorageSync('userPhone', data.user_phone)
|
||
this.syncUserInfo(openId)
|
||
uni.showToast({ title: '注册成功' })
|
||
setTimeout(() => uni.navigateBack(), 1500)
|
||
} else {
|
||
uni.showToast({ title: res.msg || '注册失败', icon: 'none' })
|
||
}
|
||
}).catch(() => {
|
||
uni.showToast({ title: '网络错误', icon: 'none' })
|
||
}).finally(() => {
|
||
this.submitting = false
|
||
})
|
||
},
|
||
syncUserInfo(openId) {
|
||
this.$u.api.wxOpenidLogin({ wenjuan_id: 1001, open_id: openId }).then(loginRes => {
|
||
if (loginRes.code === 0 && loginRes.Data) {
|
||
const data = loginRes.Data
|
||
if (data.user_id || data.uesr_id) uni.setStorageSync('userId', data.user_id || data.uesr_id)
|
||
if (data.user_name) uni.setStorageSync('userName', data.user_name)
|
||
if (data.user_phone) uni.setStorageSync('userPhone', data.user_phone)
|
||
}
|
||
}).catch(err => {
|
||
console.error('注册后同步用户信息失败', err)
|
||
})
|
||
},
|
||
},
|
||
beforeDestroy() {
|
||
if (this.timer) {
|
||
clearInterval(this.timer)
|
||
this.timer = null
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
page {
|
||
background: linear-gradient(135deg, #FFF8ED 0%, #FFE9C4 100%);
|
||
}
|
||
|
||
.register-page {
|
||
padding: 60rpx 40rpx;
|
||
min-height: 100vh;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.header {
|
||
margin-bottom: 50rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.header-title {
|
||
font-size: 40rpx;
|
||
font-weight: bold;
|
||
color: #5D533D;
|
||
display: block;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
|
||
.header-desc {
|
||
font-size: 26rpx;
|
||
color: #8B7355;
|
||
}
|
||
|
||
.form {
|
||
background: rgba(255, 255, 255, 0.95);
|
||
border-radius: 24rpx;
|
||
padding: 50rpx 40rpx;
|
||
box-shadow: 0 8rpx 40rpx rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
.field {
|
||
margin-bottom: 36rpx;
|
||
}
|
||
|
||
.label {
|
||
font-size: 28rpx;
|
||
font-weight: 500;
|
||
color: #5D533D;
|
||
margin-bottom: 16rpx;
|
||
display: block;
|
||
padding-left: 8rpx;
|
||
}
|
||
|
||
.input-wrap {
|
||
display: flex;
|
||
align-items: center;
|
||
height: 88rpx;
|
||
border: 2rpx solid #F0E4D0;
|
||
border-radius: 12rpx;
|
||
background: #FEFCF8;
|
||
padding: 0 24rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.input-wrap:focus-within {
|
||
border-color: #FD5401;
|
||
box-shadow: 0 0 0 4rpx rgba(253, 84, 1, 0.08);
|
||
}
|
||
|
||
.input-icon {
|
||
font-size: 32rpx;
|
||
margin-right: 16rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.input {
|
||
height: 100%;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
flex: 1;
|
||
border: none;
|
||
background: transparent;
|
||
outline: none;
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.name-tip {
|
||
display: block;
|
||
font-size: 22rpx;
|
||
color: #E4393C;
|
||
line-height: 1.5;
|
||
margin-top: 12rpx;
|
||
padding: 12rpx 16rpx;
|
||
background: #FFEFE9;
|
||
border-radius: 12rpx;
|
||
}
|
||
|
||
.field-row {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.code-input-wrap {
|
||
flex: 1;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.code-btn {
|
||
flex-shrink: 0;
|
||
height: 88rpx;
|
||
line-height: 88rpx;
|
||
padding: 0 28rpx;
|
||
font-size: 26rpx;
|
||
color: #FD5401;
|
||
background: #FFF0E6;
|
||
border: none;
|
||
border-radius: 12rpx;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.code-btn.disabled {
|
||
color: #B8A898;
|
||
background: #F0E8E0;
|
||
}
|
||
|
||
.submit-btn {
|
||
width: 100%;
|
||
height: 96rpx;
|
||
line-height: 96rpx;
|
||
background: linear-gradient(135deg, #FD5401, #FF7A3D);
|
||
color: #fff;
|
||
font-size: 34rpx;
|
||
font-weight: 600;
|
||
border: none;
|
||
border-radius: 16rpx;
|
||
margin-top: 20rpx;
|
||
box-shadow: 0 6rpx 20rpx rgba(253, 84, 1, 0.3);
|
||
}
|
||
|
||
.submit-btn.disabled {
|
||
opacity: 0.5;
|
||
}
|
||
|
||
.agree-row {
|
||
display: flex;
|
||
align-items: center;
|
||
margin: -16rpx 8rpx 28rpx;
|
||
}
|
||
|
||
.agree-checkbox {
|
||
width: 36rpx;
|
||
height: 36rpx;
|
||
border: 2rpx solid #CCC;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
margin-right: 12rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.agree-checkbox.checked {
|
||
border-color: #FD5401;
|
||
background: #FD5401;
|
||
}
|
||
|
||
.agree-check-mark {
|
||
font-size: 22rpx;
|
||
color: #fff;
|
||
font-weight: 700;
|
||
line-height: 1;
|
||
}
|
||
|
||
.agree-text {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 24rpx;
|
||
color: #8B7355;
|
||
}
|
||
|
||
.agree-link {
|
||
color: #FD5401;
|
||
}
|
||
</style> |