Files
airz-uniapp/packages/account/security/security.uvue
T
hujun 71b3c25695 feat: 优化账户切换时的页面状态一致性,增加登录回跳校验和课程阅读新逻辑
- 增加账户状态监听定时器,页面切换时自动校验账户归属,避免跨账户操作
- 新增登录回跳路径校验函数,限制仅允许指定页面回跳,防止非法跳转
- 课程页改为整篇连续阅读,底部仅一次标记已读,兼容历史记录
- 完善助手、对比页、资料填写页等多处的账户状态校验逻辑,防止错版数据提交
- 优化账户资料请求逻辑,增加版本校验,避免旧请求覆盖新数据
2026-10-07 10:01:05 +08:00

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>