fix:修复了很多不规范用词,更改了手机绑定校验逻辑,调整最大限制购买次数为200次。
This commit is contained in:
parent
5dfb2c3ecb
commit
b959e634d2
@ -258,6 +258,18 @@ export function modifyUser(user_id, data) {
|
|||||||
return authRequest({ url: `/api/app/users/${user_id}`, method: 'PUT', data })
|
return authRequest({ url: `/api/app/users/${user_id}`, method: 'PUT', data })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户资料信息(新接口)
|
||||||
|
* @returns {Promise} 用户资料信息 { id, nickname, avatar, mobile, balance, invite_code, inviter_id }
|
||||||
|
*/
|
||||||
|
export function getUserProfile() {
|
||||||
|
return authRequest({ url: '/api/app/users/profile', method: 'GET' })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户信息(兼容旧接口)
|
||||||
|
* @deprecated 建议使用 getUserProfile
|
||||||
|
*/
|
||||||
export function getUserInfo() {
|
export function getUserInfo() {
|
||||||
const user_info = uni.getStorageSync('user_info')
|
const user_info = uni.getStorageSync('user_info')
|
||||||
if (user_info) return Promise.resolve(user_info)
|
if (user_info) return Promise.resolve(user_info)
|
||||||
|
|||||||
@ -41,7 +41,13 @@
|
|||||||
<view class="action-row">
|
<view class="action-row">
|
||||||
<view class="stepper" @tap.stop>
|
<view class="stepper" @tap.stop>
|
||||||
<text class="step-btn minus" @tap="updateCount(pkg.id, -1)">-</text>
|
<text class="step-btn minus" @tap="updateCount(pkg.id, -1)">-</text>
|
||||||
<text class="step-val">{{ counts[pkg.id] || 1 }}</text>
|
<input
|
||||||
|
class="step-input"
|
||||||
|
type="number"
|
||||||
|
:value="counts[pkg.id] || 1"
|
||||||
|
@input="onInputCount(pkg.id, $event)"
|
||||||
|
@blur="onBlurCount(pkg.id)"
|
||||||
|
/>
|
||||||
<text class="step-btn plus" @tap="updateCount(pkg.id, 1)">+</text>
|
<text class="step-btn plus" @tap="updateCount(pkg.id, 1)">+</text>
|
||||||
</view>
|
</view>
|
||||||
<button class="btn-buy" :loading="purchasingId === pkg.id" @tap.stop="handlePurchase(pkg)">
|
<button class="btn-buy" :loading="purchasingId === pkg.id" @tap.stop="handlePurchase(pkg)">
|
||||||
@ -75,11 +81,33 @@ const counts = ref({})
|
|||||||
function updateCount(pkgId, delta) {
|
function updateCount(pkgId, delta) {
|
||||||
const current = counts.value[pkgId] || 1
|
const current = counts.value[pkgId] || 1
|
||||||
const newVal = current + delta
|
const newVal = current + delta
|
||||||
if (newVal >= 1 && newVal <= 99) {
|
if (newVal >= 1 && newVal <= 200) {
|
||||||
counts.value[pkgId] = newVal
|
counts.value[pkgId] = newVal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onInputCount(pkgId, e) {
|
||||||
|
const val = parseInt(e.detail.value) || 1
|
||||||
|
// 允许输入过程中的临时值(如空字符串),但限制范围
|
||||||
|
if (val >= 1 && val <= 200) {
|
||||||
|
counts.value[pkgId] = val
|
||||||
|
} else if (val < 1) {
|
||||||
|
counts.value[pkgId] = 1
|
||||||
|
} else if (val > 200) {
|
||||||
|
counts.value[pkgId] = 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onBlurCount(pkgId) {
|
||||||
|
// 失去焦点时确保值在有效范围内
|
||||||
|
const current = counts.value[pkgId] || 1
|
||||||
|
if (current < 1) {
|
||||||
|
counts.value[pkgId] = 1
|
||||||
|
} else if (current > 200) {
|
||||||
|
counts.value[pkgId] = 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watch(() => props.visible, (val) => {
|
watch(() => props.visible, (val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
fetchPackages()
|
fetchPackages()
|
||||||
@ -349,18 +377,29 @@ function handleClose() {
|
|||||||
font-size: 32rpx;
|
font-size: 32rpx;
|
||||||
color: #4B5563;
|
color: #4B5563;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.minus {
|
.minus {
|
||||||
color: #9CA3AF;
|
color: #9CA3AF;
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-val {
|
.step-input {
|
||||||
width: 40rpx;
|
width: 60rpx;
|
||||||
|
height: 44rpx;
|
||||||
|
line-height: 44rpx;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #1F2937;
|
color: #1F2937;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: #9CA3AF;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -44,11 +44,10 @@
|
|||||||
<view v-else-if="gamePassRemaining <= 0" class="radio-disabled" />
|
<view v-else-if="gamePassRemaining <= 0" class="radio-disabled" />
|
||||||
</view>
|
</view>
|
||||||
<view class="game-pass-info">
|
<view class="game-pass-info">
|
||||||
<text class="game-pass-label" :class="{ 'text-disabled': gamePassRemaining <= 0 }">🎮 使用次数卡</text>
|
<text class="game-pass-label" :class="{ 'text-disabled': gamePassRemaining <= 0 }">剩余次数</text>
|
||||||
<text class="game-pass-count" v-if="gamePassRemaining > 0">剩余 {{ gamePassRemaining }} 次</text>
|
<text class="game-pass-count" v-if="gamePassRemaining > 0">{{ gamePassRemaining }} 次</text>
|
||||||
<text class="game-pass-count text-disabled" v-else>暂无可用次数卡</text>
|
<text class="game-pass-count text-disabled" v-else>暂无可用次数卡</text>
|
||||||
</view>
|
</view>
|
||||||
<text v-if="gamePassRemaining > 0" class="game-pass-free">免费畅玩</text>
|
|
||||||
</view>
|
</view>
|
||||||
<view v-if="!useGamePass" class="divider-line">
|
<view v-if="!useGamePass" class="divider-line">
|
||||||
<text class="divider-text">或选择其他支付方式</text>
|
<text class="divider-text">或选择其他支付方式</text>
|
||||||
@ -842,7 +841,7 @@ function handleConfirm() {
|
|||||||
background: linear-gradient(135deg, #10B981, #059669);
|
background: linear-gradient(135deg, #10B981, #059669);
|
||||||
border-color: #059669;
|
border-color: #059669;
|
||||||
|
|
||||||
.game-pass-label, .game-pass-count, .game-pass-free {
|
.game-pass-label, .game-pass-count {
|
||||||
color: #FFFFFF;
|
color: #FFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -902,15 +901,6 @@ function handleConfirm() {
|
|||||||
margin-top: 4rpx;
|
margin-top: 4rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-pass-free {
|
|
||||||
font-size: $font-sm;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #10B981;
|
|
||||||
padding: 6rpx 16rpx;
|
|
||||||
background: rgba(16, 185, 129, 0.1);
|
|
||||||
border-radius: $radius-md;
|
|
||||||
}
|
|
||||||
|
|
||||||
.divider-line {
|
.divider-line {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@ -215,8 +215,8 @@ async function fetchProductMeta(productId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
// 检查手机号绑定状态
|
// 检查手机号绑定状态(快速检查本地缓存)
|
||||||
if (!checkPhoneBound()) return
|
if (!checkPhoneBoundSync()) return
|
||||||
|
|
||||||
// Check for external tab switch request
|
// Check for external tab switch request
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -180,8 +180,8 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onLoad() {
|
onLoad() {
|
||||||
// 检查手机号绑定状态
|
// 检查手机号绑定状态(快速检查本地缓存)
|
||||||
if (!checkPhoneBound()) return
|
if (!checkPhoneBoundSync()) return
|
||||||
|
|
||||||
// 延迟 200ms 首次加载,让 Token/Session 有机会就绪
|
// 延迟 200ms 首次加载,让 Token/Session 有机会就绪
|
||||||
// 同时避免页面动画卡顿
|
// 同时避免页面动画卡顿
|
||||||
|
|||||||
@ -468,9 +468,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import {
|
import {
|
||||||
getUserInfo, getUserStats, getPointsBalance, getUserPoints, getUserCoupons, getItemCards,
|
getUserInfo, getUserStats, getPointsBalance, getUserPoints, getUserCoupons, getItemCards,
|
||||||
getUserTasks, getTaskProgress, getInviteRecords, modifyUser
|
getUserTasks, getTaskProgress, getInviteRecords, modifyUser, getUserProfile
|
||||||
} from '../../api/appUser.js'
|
} from '../../api/appUser.js'
|
||||||
import { checkPhoneBound } from '../../utils/checkPhone.js'
|
import { checkPhoneBoundSync } from '../../utils/checkPhone.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
@ -537,8 +537,8 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onShow() {
|
onShow() {
|
||||||
// 检查手机号绑定状态
|
// 检查手机号绑定状态(快速检查本地缓存)
|
||||||
if (!checkPhoneBound()) return
|
if (!checkPhoneBoundSync()) return
|
||||||
|
|
||||||
this.loadUserInfo()
|
this.loadUserInfo()
|
||||||
},
|
},
|
||||||
@ -739,6 +739,45 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
// 优先使用新的 profile API
|
||||||
|
const profile = await getUserProfile()
|
||||||
|
|
||||||
|
if (profile) {
|
||||||
|
console.log('[Mine] 从 profile API 获取用户信息:', profile)
|
||||||
|
this.userId = profile.id
|
||||||
|
this.nickname = profile.nickname
|
||||||
|
this.avatar = profile.avatar
|
||||||
|
this.title = profile.title || ''
|
||||||
|
this.inviteCode = profile.invite_code
|
||||||
|
this.pointsBalance = this.normalizePointsBalance(profile.balance)
|
||||||
|
this.mobile = profile.mobile || ''
|
||||||
|
|
||||||
|
// 更新缓存
|
||||||
|
const cachedUser = uni.getStorageSync('user_info') || {}
|
||||||
|
cachedUser.id = profile.id
|
||||||
|
cachedUser.nickname = profile.nickname
|
||||||
|
cachedUser.avatar = profile.avatar
|
||||||
|
cachedUser.title = profile.title
|
||||||
|
cachedUser.invite_code = profile.invite_code
|
||||||
|
cachedUser.mobile = profile.mobile
|
||||||
|
cachedUser.points_balance = this.pointsBalance
|
||||||
|
uni.setStorageSync('user_info', cachedUser)
|
||||||
|
uni.setStorageSync('user_id', profile.id)
|
||||||
|
|
||||||
|
// 如果有手机号,更新缓存
|
||||||
|
if (profile.mobile) {
|
||||||
|
uni.setStorageSync('phone_number', profile.mobile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load stats
|
||||||
|
const s = await getUserStats(profile.id)
|
||||||
|
if (s) this.stats = { ...this.stats, ...s }
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 降级到旧逻辑
|
||||||
|
console.log('[Mine] profile API 无数据,使用降级逻辑')
|
||||||
// 先尝试从缓存获取基础信息
|
// 先尝试从缓存获取基础信息
|
||||||
const cachedUser = uni.getStorageSync('user_info')
|
const cachedUser = uni.getStorageSync('user_info')
|
||||||
const cachedUserId = uni.getStorageSync('user_id')
|
const cachedUserId = uni.getStorageSync('user_id')
|
||||||
@ -789,7 +828,7 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error('[Mine] loadUserInfo 错误:', e)
|
||||||
// If 401, maybe clear token
|
// If 401, maybe clear token
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -414,8 +414,8 @@ async function onRedeemTap(item) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
// 检查手机号绑定状态
|
// 检查手机号绑定状态(快速检查本地缓存)
|
||||||
if (!checkPhoneBound()) return
|
if (!checkPhoneBoundSync()) return
|
||||||
|
|
||||||
const token = uni.getStorageSync('token')
|
const token = uni.getStorageSync('token')
|
||||||
if (token) {
|
if (token) {
|
||||||
|
|||||||
@ -1,31 +1,80 @@
|
|||||||
|
import { getUserProfile } from '../api/appUser'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查手机号绑定状态
|
* 检查手机号绑定状态
|
||||||
* 如果未绑定手机号,则跳转到登录页面进行绑定
|
* 如果未绑定手机号,则跳转到登录页面进行绑定
|
||||||
|
* @returns {Promise<boolean>} 是否已绑定手机号
|
||||||
|
*/
|
||||||
|
export async function checkPhoneBound() {
|
||||||
|
try {
|
||||||
|
// 调用新的用户资料接口
|
||||||
|
const profile = await getUserProfile()
|
||||||
|
|
||||||
|
console.log('[checkPhoneBound] 用户资料:', profile)
|
||||||
|
|
||||||
|
// 检查是否已绑定手机号
|
||||||
|
const mobile = profile?.mobile
|
||||||
|
|
||||||
|
if (mobile) {
|
||||||
|
console.log('[checkPhoneBound] 已检测到手机号,允许通过:', mobile)
|
||||||
|
// 缓存手机号
|
||||||
|
uni.setStorageSync('phone_number', mobile)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 未绑定手机号,显示提示并跳转
|
||||||
|
console.warn('[checkPhoneBound] 未检测到手机号,提示用户绑定')
|
||||||
|
uni.showModal({
|
||||||
|
title: '需要绑定手机号',
|
||||||
|
content: '为了账号安全,请先绑定手机号',
|
||||||
|
showCancel: false,
|
||||||
|
confirmText: '去绑定',
|
||||||
|
success: () => {
|
||||||
|
uni.navigateTo({ url: '/pages/login/index?mode=sms' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return false
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[checkPhoneBound] 获取用户信息失败:', err)
|
||||||
|
|
||||||
|
// 请求失败时,降级检查本地缓存
|
||||||
|
const phoneNumber = uni.getStorageSync('phone_number') || ''
|
||||||
|
console.log('[checkPhoneBound] 降级检查本地缓存:', phoneNumber ? phoneNumber : '未找到')
|
||||||
|
|
||||||
|
if (phoneNumber) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 本地也没有,提示重新登录
|
||||||
|
uni.showModal({
|
||||||
|
title: '提示',
|
||||||
|
content: '获取用户信息失败,请重新登录',
|
||||||
|
showCancel: false,
|
||||||
|
confirmText: '去登录',
|
||||||
|
success: () => {
|
||||||
|
uni.navigateTo({ url: '/pages/login/index' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步检查手机号绑定状态(仅检查本地缓存)
|
||||||
* @returns {boolean} 是否已绑定手机号
|
* @returns {boolean} 是否已绑定手机号
|
||||||
*/
|
*/
|
||||||
export function checkPhoneBound() {
|
export function checkPhoneBoundSync() {
|
||||||
// 直接检查 phone_number 缓存中是否有手机号
|
|
||||||
const phoneNumber = uni.getStorageSync('phone_number') || ''
|
const phoneNumber = uni.getStorageSync('phone_number') || ''
|
||||||
|
|
||||||
console.log('[checkPhoneBound] 检查 phone_number 缓存:', phoneNumber ? phoneNumber : '未找到')
|
console.log('[checkPhoneBoundSync] 检查 phone_number 缓存:', phoneNumber ? phoneNumber : '未找到')
|
||||||
|
|
||||||
// 如果已绑定手机号,直接返回
|
|
||||||
if (phoneNumber) {
|
if (phoneNumber) {
|
||||||
console.log('[checkPhoneBound] 已检测到手机号,允许通过:', phoneNumber)
|
console.log('[checkPhoneBoundSync] 已检测到手机号,允许通过:', phoneNumber)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 未绑定手机号,显示提示并跳转
|
console.warn('[checkPhoneBoundSync] 未检测到手机号')
|
||||||
console.warn('[checkPhoneBound] 未检测到手机号,提示用户绑定')
|
|
||||||
uni.showModal({
|
|
||||||
title: '需要绑定手机号',
|
|
||||||
content: '为了账号安全,请先绑定手机号',
|
|
||||||
showCancel: false,
|
|
||||||
confirmText: '去绑定',
|
|
||||||
success: () => {
|
|
||||||
uni.navigateTo({ url: '/pages/login/index?mode=sms' })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user