feat: 优化账户切换时的页面状态一致性,增加登录回跳校验和课程阅读新逻辑
- 增加账户状态监听定时器,页面切换时自动校验账户归属,避免跨账户操作 - 新增登录回跳路径校验函数,限制仅允许指定页面回跳,防止非法跳转 - 课程页改为整篇连续阅读,底部仅一次标记已读,兼容历史记录 - 完善助手、对比页、资料填写页等多处的账户状态校验逻辑,防止错版数据提交 - 优化账户资料请求逻辑,增加版本校验,避免旧请求覆盖新数据
This commit is contained in:
@@ -2,8 +2,8 @@
|
||||
<view class="page" :style="pageStyle()"><AppHeader title="更换手机号" />
|
||||
<scroll-view scroll-y :style="contentStyle(96, false)"><view class="account-form-content" :style="bottomStyle(40)">
|
||||
<text class="form-title">验证并绑定新手机号</text><text class="form-description">请分别验证当前号码和新号码,确保账户由您本人操作。</text>
|
||||
<view class="form-card"><text class="form-label">当前手机号 {{ maskPhone(phone) }}</text><SecurityCode v-model="currentCode" :disabled="submitting" purpose="phone-current" @error="codeError" @sent="errorMessage = ''" /></view>
|
||||
<view class="form-card"><text class="form-label">新手机号</text><input v-model="newPhone" class="account-input new-phone" :disabled="submitting" type="number" maxlength="11" placeholder="请输入新的 11 位手机号" /><SecurityCode v-model="newCode" :disabled="submitting || !validPhone(newPhone) || newPhone == phone" purpose="phone-new" :phone="newPhone" @error="codeError" @sent="errorMessage = ''" /></view>
|
||||
<view class="form-card"><text class="form-label">当前手机号 {{ maskPhone(phone) }}</text><SecurityCode v-model="currentCode" :disabled="submitting" :active="pageVisible" :ownerToken="ownerToken" purpose="phone-current" @error="codeError" @sent="errorMessage = ''" /></view>
|
||||
<view class="form-card"><text class="form-label">新手机号</text><input v-model="newPhone" class="account-input new-phone" :disabled="submitting" type="number" maxlength="11" placeholder="请输入新的 11 位手机号" /><SecurityCode v-model="newCode" :disabled="submitting || !validPhone(newPhone) || newPhone == phone" :active="pageVisible" :ownerToken="ownerToken" purpose="phone-new" :phone="newPhone" @error="codeError" @sent="errorMessage = ''" /></view>
|
||||
<text class="form-hint">换绑成功后需要使用新手机号登录。若原号码已无法接收短信,请通过官方客服核验身份后处理。</text>
|
||||
<text v-if="errorMessage.length > 0" class="form-error">{{ errorMessage }}</text>
|
||||
<button class="primary-button form-submit" :disabled="submitting" @click="submit">{{ submitting ? '提交中…' : '确认更换' }}</button>
|
||||
@@ -18,20 +18,35 @@
|
||||
import { getAccountProfile, maskPhone, validPhone, changeAccountPhone } from '@/packages/account/services/account.uts'
|
||||
const { pageStyle, contentStyle, bottomStyle } = usePageLayout()
|
||||
const phone = ref(''); const newPhone = ref(''); const currentCode = ref(''); const newCode = ref(''); const submitting = ref(false); const errorMessage = ref('')
|
||||
onLoad(() => { if (getSession() == null) { uni.redirectTo({ url: '/packages/account/login/login' }); return }; phone.value = getAccountProfile().phone })
|
||||
const codeError = (message: string) => { errorMessage.value = message }
|
||||
const ownerToken = ref(''); const pageVisible = ref(false)
|
||||
let ownerId = ''; let generation = 0; let accountTimer = 0
|
||||
const clearSecrets = () => { currentCode.value = ''; newCode.value = ''; newPhone.value = '' }
|
||||
const stopAccountTimer = () => { clearInterval(accountTimer); accountTimer = 0 }
|
||||
const sameOwner = (): boolean => {
|
||||
if (!pageVisible.value) return false
|
||||
const session = getSession()
|
||||
if (ownerToken.value.length > 0 && session?.getString('token') == ownerToken.value && session?.getString('userId') == ownerId) return true
|
||||
generation++; clearSecrets(); phone.value = ''; errorMessage.value = ''; stopAccountTimer()
|
||||
uni.redirectTo({ url: session == null ? '/packages/account/login/login' : '/packages/account/security/security' })
|
||||
return false
|
||||
}
|
||||
onLoad(() => { const session = getSession(); ownerToken.value = session?.getString('token') ?? ''; ownerId = session?.getString('userId') ?? ''; phone.value = getAccountProfile().phone })
|
||||
onShow(() => { pageVisible.value = true; generation++; stopAccountTimer(); if (sameOwner()) accountTimer = setInterval(() => { sameOwner() }, 1000) })
|
||||
const codeError = (message: string) => { if (sameOwner()) errorMessage.value = message }
|
||||
const submit = async () => {
|
||||
if (submitting.value) return
|
||||
if (!sameOwner() || submitting.value) return
|
||||
submitting.value = true; errorMessage.value = ''
|
||||
const view = generation; const token = ownerToken.value; const userId = ownerId
|
||||
try {
|
||||
if (getAccountProfile().phone != phone.value) throw new Error('登录状态已变化,请重新进入页面')
|
||||
await changeAccountPhone(newPhone.value, currentCode.value, newCode.value)
|
||||
currentCode.value = ''; newCode.value = ''; clearSession(); uni.reLaunch({ url: '/packages/account/login/login' }); uni.showToast({ title: '手机号已更换,请重新登录', icon: 'none' })
|
||||
} catch (error) { errorMessage.value = error instanceof Error ? error.message : '更换失败,请稍后重试' }
|
||||
if (getSession()?.getString('token') != token || getSession()?.getString('userId') != userId) return
|
||||
clearSecrets(); clearSession()
|
||||
if (view == generation && pageVisible.value) { uni.reLaunch({ url: '/packages/account/login/login' }); uni.showToast({ title: '手机号已更换,请重新登录', icon: 'none' }) }
|
||||
} catch (error) { if (view == generation && sameOwner()) errorMessage.value = error instanceof Error ? error.message : '更换失败,请稍后重试' }
|
||||
finally { submitting.value = false }
|
||||
}
|
||||
onHide(() => { currentCode.value = ''; newCode.value = '' })
|
||||
onUnload(() => { currentCode.value = ''; newCode.value = '' })
|
||||
onHide(() => { pageVisible.value = false; generation++; stopAccountTimer(); clearSecrets(); errorMessage.value = '' })
|
||||
onUnload(() => { pageVisible.value = false; generation++; stopAccountTimer(); clearSecrets(); phone.value = '' })
|
||||
</script>
|
||||
<style>
|
||||
@import '../styles/forms.css';
|
||||
|
||||
Reference in New Issue
Block a user