init: llpreheat 学法送演唱会门票 H5项目

This commit is contained in:
lcj
2026-09-03 10:21:11 +08:00
commit 305e22ddc5
223 changed files with 46261 additions and 0 deletions
+340
View File
@@ -0,0 +1,340 @@
<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>