feat: 优化账户切换时的页面状态一致性,增加登录回跳校验和课程阅读新逻辑
- 增加账户状态监听定时器,页面切换时自动校验账户归属,避免跨账户操作 - 新增登录回跳路径校验函数,限制仅允许指定页面回跳,防止非法跳转 - 课程页改为整篇连续阅读,底部仅一次标记已读,兼容历史记录 - 完善助手、对比页、资料填写页等多处的账户状态校验逻辑,防止错版数据提交 - 优化账户资料请求逻辑,增加版本校验,避免旧请求覆盖新数据
This commit is contained in:
@@ -77,7 +77,7 @@
|
||||
const step = ref(0)
|
||||
const assessmentType = ref('personal')
|
||||
const form = ref<AssessmentForm>(emptyAssessmentForm())
|
||||
let ownerToken = ''; let goingToConfirm = false
|
||||
let ownerToken = ''; let goingToConfirm = false; let visible = false; let accountTimer = 0
|
||||
const sameOwner = (): boolean => { const session = getSession(); return session != null && session['token'] == ownerToken }
|
||||
const customCity = ref('')
|
||||
const cityChanged = (city: string) => { form.value.city = city; if (city != '其他城市') customCity.value = '' }
|
||||
@@ -88,6 +88,24 @@
|
||||
const titles = ['基本信息', '经营 / 收入信息', '资产 / 负债信息', '资料上传 / 授权']
|
||||
const uploadNames = computed((): string[] => assessmentType.value == 'enterprise' ? ['营业执照', '银行流水', '经营证明'] : ['身份证正面', '身份证反面', '银行卡', '收入证明'])
|
||||
let initialized = false
|
||||
const stopAccountTimer = () => { if (accountTimer != 0) clearInterval(accountTimer); accountTimer = 0 }
|
||||
const ensureOwner = (): boolean => {
|
||||
if (!visible) return false
|
||||
if (sameOwner()) return true
|
||||
const session = getSession()
|
||||
ownerToken = session?.getString('token') ?? ''
|
||||
editGeneration++; initialized = false; stopAccountTimer(); clearAssessmentFlow()
|
||||
form.value = emptyAssessmentForm(); documents.value = []; customCity.value = ''; step.value = 0
|
||||
documentConsent.value = false; dataConsent.value = false; authorizations.value.forEach((item) => { item.selected = false })
|
||||
baseRevisionId = ''; editLoading.value = false; editError.value = '账户已变化,请返回重新填写。'
|
||||
if (session == null) uni.redirectTo({ url: '/packages/account/login/login' })
|
||||
return false
|
||||
}
|
||||
const startAccountTimer = () => {
|
||||
stopAccountTimer()
|
||||
if (ownerToken.length == 0) return
|
||||
accountTimer = setInterval(() => { if (visible && !sameOwner()) ensureOwner() }, 1000)
|
||||
}
|
||||
const rememberInput = () => {
|
||||
if (!initialized || !sameOwner()) return
|
||||
const source = form.value
|
||||
@@ -110,15 +128,15 @@
|
||||
initialized = true
|
||||
rememberInput()
|
||||
}
|
||||
const switchType = (type: string) => { if (editId.value.length > 0 || assessmentType.value == type) return; rememberInput(); restore(type); step.value = 0; rememberInput() }
|
||||
const switchType = (type: string) => { if (!ensureOwner() || editId.value.length > 0 || assessmentType.value == type) return; rememberInput(); restore(type); step.value = 0; rememberInput() }
|
||||
const loadEdit = async (type: string) => {
|
||||
const ticket = ++editGeneration; editLoading.value = true
|
||||
try {
|
||||
const saved = await fetchAssessmentEdit(editId.value)
|
||||
if (ticket != editGeneration || !sameOwner()) return
|
||||
if (ticket != editGeneration || !ensureOwner()) return
|
||||
baseRevisionId = saved.getString('baseRevisionId') ?? ''
|
||||
writeAssessmentFlow(ownerToken, saved); restore(saved.getString('type') ?? type)
|
||||
} catch (err) { if (ticket == editGeneration && sameOwner()) editError.value = err instanceof Error ? err.message : '资料读取失败,请返回重试。' }
|
||||
} catch (err) { if (ticket == editGeneration && ensureOwner()) editError.value = err instanceof Error ? err.message : '资料读取失败,请返回重试。' }
|
||||
finally { if (ticket == editGeneration) editLoading.value = false }
|
||||
}
|
||||
onLoad((options) => {
|
||||
@@ -134,13 +152,16 @@
|
||||
loadEdit(type)
|
||||
})
|
||||
onShow(() => {
|
||||
goingToConfirm = false
|
||||
if (initialized && !sameOwner()) { initialized = false; form.value = emptyAssessmentForm(); clearAssessmentFlow(); uni.redirectTo({ url: '/packages/account/login/login' }) }
|
||||
visible = true; stopAccountTimer()
|
||||
goingToConfirm = false
|
||||
if (initialized && !sameOwner()) ensureOwner()
|
||||
const input = getAssessmentInput(assessmentType.value)
|
||||
if (initialized && input != null && typeof input['step'] == 'number') step.value = Math.max(0, Math.min(3, input['step'] as number))
|
||||
startAccountTimer()
|
||||
})
|
||||
// 离开填写流程即丢弃未提交内容;进入确认页时只在内存传递。
|
||||
onHide(() => {
|
||||
visible = false; stopAccountTimer()
|
||||
if (!goingToConfirm) {
|
||||
editGeneration++; if (editId.value.length > 0) editError.value = '已离开修改流程,请返回档案重新进入。'
|
||||
// 离页清空资料但不切换步骤,避免卸载时又挂载另一组原生输入组件。
|
||||
@@ -149,7 +170,7 @@
|
||||
authorizations.value.forEach((item) => { item.selected = false })
|
||||
}
|
||||
})
|
||||
onUnload(() => { editGeneration++; initialized = false; clearAssessmentFlow() })
|
||||
onUnload(() => { visible = false; stopAccountTimer(); editGeneration++; initialized = false; clearAssessmentFlow() })
|
||||
// 页内前后步骤只维护当前内存状态,返回入口后不保留填写内容。
|
||||
onBackPress((): boolean => { rememberInput(); if (step.value > 0) { step.value--; rememberInput(); return true }; return false })
|
||||
const previous = () => { rememberInput(); if (step.value > 0) step.value--; rememberInput() }
|
||||
@@ -160,17 +181,22 @@
|
||||
uni.showToast({ title: name + '已失效,请重新选择', icon: 'none' })
|
||||
}
|
||||
const chooseDocument = (name: string) => {
|
||||
if (!ensureOwner()) return
|
||||
const ticket = editGeneration
|
||||
uni.chooseImage({ count: 1, sizeType: ['compressed'], sourceType: ['album', 'camera'], success: (result) => {
|
||||
if (result.tempFilePaths.length == 0) return
|
||||
if (ticket != editGeneration || !ensureOwner() || result.tempFilePaths.length == 0) return
|
||||
documents.value = documents.value.filter((file) => file.name != name)
|
||||
const document: SelectedDocument = { name, path: result.tempFilePaths[0] }
|
||||
documents.value.push(document); rememberInput()
|
||||
}, fail: (error) => { if (!error.errMsg.includes('cancel')) uni.showToast({ title: '选择失败,请重试或检查相册权限', icon: 'none' }) } })
|
||||
}, fail: (error) => { if (ticket == editGeneration && ensureOwner() && !error.errMsg.includes('cancel')) uni.showToast({ title: '选择失败,请重试或检查相册权限', icon: 'none' }) } })
|
||||
}
|
||||
const documentAction = (name: string) => {
|
||||
if (!ensureOwner()) return
|
||||
const ticket = editGeneration
|
||||
const path = documentPath(name)
|
||||
if (path.length == 0) { chooseDocument(name); return }
|
||||
uni.showActionSheet({ itemList: ['预览图片', '重新选择', '移除资料'], success: (result) => {
|
||||
if (ticket != editGeneration || !ensureOwner()) return
|
||||
if (result.tapIndex == 0) uni.previewImage({ urls: [path], fail: () => { uni.showToast({ title: '本地图片已失效,请重新选择', icon: 'none' }) } })
|
||||
else if (result.tapIndex == 1) chooseDocument(name)
|
||||
else if (result.tapIndex == 2) { documents.value = documents.value.filter((file) => file.name != name); rememberInput() }
|
||||
@@ -196,7 +222,7 @@
|
||||
if (message.length == 0) return true
|
||||
uni.showToast({ title: message, icon: 'none' }); return false
|
||||
}
|
||||
const next = () => { if (editLoading.value || editError.value.length > 0 || !sameOwner()) return; if (!validateStep()) return; if (step.value < 3) { step.value++; rememberInput() } else { rememberInput(); goingToConfirm = true; uni.navigateTo({ url: '/packages/finance/confirm/confirm', fail: () => { goingToConfirm = false } }) } }
|
||||
const next = () => { if (!ensureOwner() || editLoading.value || editError.value.length > 0) return; if (!validateStep()) return; if (step.value < 3) { step.value++; rememberInput() } else { rememberInput(); goingToConfirm = true; uni.navigateTo({ url: '/packages/finance/confirm/confirm', fail: () => { goingToConfirm = false } }) } }
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user