- 增加账户状态监听定时器,页面切换时自动校验账户归属,避免跨账户操作 - 新增登录回跳路径校验函数,限制仅允许指定页面回跳,防止非法跳转 - 课程页改为整篇连续阅读,底部仅一次标记已读,兼容历史记录 - 完善助手、对比页、资料填写页等多处的账户状态校验逻辑,防止错版数据提交 - 优化账户资料请求逻辑,增加版本校验,避免旧请求覆盖新数据
56 lines
4.4 KiB
Plaintext
56 lines
4.4 KiB
Plaintext
<template>
|
|
<view class="page" :style="pageStyle()"><AppHeader title="账户安全" />
|
|
<scroll-view scroll-y :style="contentStyle(96, false)"><view class="security-content" :style="bottomStyle(40)">
|
|
<view class="security-intro"><view class="shield-surface"><image class="shield-icon" src="/static/icons/shield.svg" mode="aspectFit" /></view><view class="intro-copy"><text class="intro-title">守护您的账户</text><text class="intro-desc">妥善保管密码与短信验证码</text></view></view>
|
|
<view class="security-list">
|
|
<view class="security-row" @click="go('password/password')"><view class="row-copy"><text class="row-title">修改登录密码</text><text class="row-desc">通过当前密码验证身份</text></view><AppIcon name="chevron-right" :size="28" /></view>
|
|
<view class="security-row" @click="go('password/password?mode=sms')"><view class="row-copy"><text class="row-title">验证码重设密码</text><text class="row-desc">忘记密码或尚未设置密码时使用</text></view><AppIcon name="chevron-right" :size="28" /></view>
|
|
<view class="security-row last-row" @click="go('change-phone/change-phone')"><view class="row-copy"><text class="row-title">绑定手机号</text><text class="row-desc">{{ maskPhone(phone) }}</text></view><text class="row-action">更换</text><AppIcon name="chevron-right" :size="28" /></view>
|
|
</view>
|
|
<view class="security-tips"><text class="tips-title">安全提醒</text><text class="tips-copy">请勿向他人提供密码或验证码。修改密码或换绑手机号成功后,需要重新登录。</text></view>
|
|
</view></scroll-view>
|
|
</view>
|
|
</template>
|
|
<script setup lang="uts">
|
|
import AppHeader from '@/components/AppHeader.uvue'
|
|
import AppIcon from '@/components/AppIcon.uvue'
|
|
import { usePageLayout } from '@/services/layout.uts'
|
|
import { getSession } from '@/services/api.uts'
|
|
import { getAccountProfile, maskPhone } from '@/packages/account/services/account.uts'
|
|
const { pageStyle, contentStyle, bottomStyle } = usePageLayout()
|
|
const phone = ref('')
|
|
let ownerToken = ''; let ownerId = ''; let pageVisible = false; let accountTimer = 0
|
|
const stopAccountTimer = () => { clearInterval(accountTimer); accountTimer = 0 }
|
|
const sameOwner = (): boolean => {
|
|
if (!pageVisible) return false
|
|
const session = getSession()
|
|
if (ownerToken.length > 0 && session?.getString('token') == ownerToken && session?.getString('userId') == ownerId) return true
|
|
phone.value = ''; stopAccountTimer()
|
|
uni.redirectTo({ url: session == null ? '/packages/account/login/login' : '/packages/account/profile/profile' })
|
|
return false
|
|
}
|
|
onShow(() => { pageVisible = true; const session = getSession(); ownerToken = session?.getString('token') ?? ''; ownerId = session?.getString('userId') ?? ''; stopAccountTimer(); if (!sameOwner()) return; phone.value = getAccountProfile().phone; accountTimer = setInterval(() => { sameOwner() }, 1000) })
|
|
onHide(() => { pageVisible = false; stopAccountTimer(); phone.value = '' })
|
|
onUnload(() => { pageVisible = false; stopAccountTimer(); phone.value = '' })
|
|
const go = (path: string) => { if (sameOwner()) uni.navigateTo({ url: '/packages/account/' + path }) }
|
|
</script>
|
|
<style>
|
|
.security-content { padding: 30rpx; }
|
|
.security-intro { padding: 26rpx; border-radius: 18rpx; background-color: #edf5ff; flex-direction: row; align-items: center; }
|
|
.shield-surface { width: 80rpx; height: 80rpx; border-radius: 22rpx; background-color: #ffffff; align-items: center; justify-content: center; margin-right: 20rpx; flex-shrink: 0; }
|
|
.shield-icon { width: 48rpx; height: 48rpx; }
|
|
.intro-copy { flex: 1; min-width: 0; }
|
|
.intro-title { font-size: 32rpx; font-weight: 700; color: #23344e; }
|
|
.intro-desc { font-size: 24rpx; line-height: 36rpx; color: #738198; margin-top: 10rpx; }
|
|
.security-list { padding: 0 26rpx; background-color: #ffffff; border-radius: 18rpx; margin-top: 24rpx; }
|
|
.security-row { flex-direction: row; align-items: center; min-height: 134rpx; padding: 24rpx 0; border-bottom: 1rpx solid #edf1f6; }
|
|
.last-row { border-bottom-width: 0; }
|
|
.row-copy { flex: 1; min-width: 0; }
|
|
.row-title { font-size: 29rpx; color: #29394f; font-weight: 600; }
|
|
.row-desc { font-size: 24rpx; line-height: 36rpx; color: #738198; margin-top: 12rpx; }
|
|
.row-action { font-size: 25rpx; color: #0868f7; margin-right: 8rpx; }
|
|
.security-tips { padding: 28rpx 8rpx; }
|
|
.tips-title { font-size: 25rpx; font-weight: 600; color: #66758a; }
|
|
.tips-copy { font-size: 24rpx; line-height: 40rpx; color: #8793a6; margin-top: 12rpx; }
|
|
</style>
|