fix(assessment): 移除本地缓存,恢复进行中测评检测
- 移除 localStorage 表单缓存(STORAGE_KEY、saveFormToStorage、restoreFormFromStorage、clearFormStorage、watch、onUnload) - 恢复 getPendingRecord API 调用和弹窗逻辑 - 恢复继续测评模式(表单自动填充、禁用编辑、按钮文案切换) - 恢复进行中测评弹窗(重新开始/继续测评)
This commit is contained in:
parent
0cbd9d4745
commit
e33f4ed8f0
|
|
@ -10,12 +10,12 @@
|
||||||
* - 进行中测评记录恢复(断点续答)
|
* - 进行中测评记录恢复(断点续答)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ref, computed, watch } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { onLoad, onUnload } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { useUserStore } from '@/store/user.js'
|
import { useUserStore } from '@/store/user.js'
|
||||||
import { useAuth } from '@/composables/useAuth.js'
|
import { useAuth } from '@/composables/useAuth.js'
|
||||||
import { usePayment } from '@/composables/usePayment.js'
|
import { usePayment } from '@/composables/usePayment.js'
|
||||||
import { getIntro, verifyInviteCode } from '@/api/assessment.js'
|
import { getIntro, verifyInviteCode, getPendingRecord } from '@/api/assessment.js'
|
||||||
import { createOrder } from '@/api/order.js'
|
import { createOrder } from '@/api/order.js'
|
||||||
import { isPhone } from '@/utils/validate.js'
|
import { isPhone } from '@/utils/validate.js'
|
||||||
import Navbar from '@/components/Navbar/index.vue'
|
import Navbar from '@/components/Navbar/index.vue'
|
||||||
|
|
@ -80,68 +80,79 @@ const inviteLoading = ref(false)
|
||||||
// 页面加载状态
|
// 页面加载状态
|
||||||
const pageLoading = ref(true)
|
const pageLoading = ref(true)
|
||||||
|
|
||||||
// 本地缓存 key
|
// 进行中测评记录
|
||||||
const STORAGE_KEY = 'assessment_info_form'
|
const pendingRecord = ref(null)
|
||||||
|
const showPendingPopup = ref(false)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存表单数据到本地
|
* 是否为继续测评模式
|
||||||
*/
|
*/
|
||||||
function saveFormToStorage() {
|
const isContinueMode = computed(() => !!pendingRecord.value)
|
||||||
const data = {
|
|
||||||
...formData.value,
|
/**
|
||||||
genderIndex: genderIndex.value,
|
* 性别数值转文本
|
||||||
ageIndex: ageIndex.value,
|
*/
|
||||||
educationIndex: educationIndex.value,
|
function getGenderLabel(val) {
|
||||||
regionValue: regionValue.value
|
return val === 1 ? '男' : val === 2 ? '女' : ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学业阶段数值转文本
|
||||||
|
*/
|
||||||
|
function getEducationStageLabel(val) {
|
||||||
|
const map = { 1: '小学及以下', 2: '初中', 3: '高中', 4: '大专' }
|
||||||
|
return map[val] || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否有进行中的测评记录
|
||||||
|
*/
|
||||||
|
async function checkPendingRecord() {
|
||||||
try {
|
try {
|
||||||
uni.setStorageSync(STORAGE_KEY, JSON.stringify(data))
|
const res = await getPendingRecord(typeId.value)
|
||||||
|
if (res && res.code === 0 && res.data) {
|
||||||
|
pendingRecord.value = res.data
|
||||||
|
showPendingPopup.value = true
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('保存表单数据失败:', e)
|
console.error('检查进行中测评失败:', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从本地还原表单数据
|
* 继续进行中的测评
|
||||||
*/
|
*/
|
||||||
function restoreFormFromStorage() {
|
function handleContinuePending() {
|
||||||
try {
|
if (!pendingRecord.value) return
|
||||||
const raw = uni.getStorageSync(STORAGE_KEY)
|
const r = pendingRecord.value
|
||||||
if (!raw) return
|
|
||||||
const data = JSON.parse(raw)
|
// 填充表单
|
||||||
formData.value.name = data.name || ''
|
formData.value.name = r.name || ''
|
||||||
formData.value.phone = data.phone || ''
|
formData.value.phone = r.phone || ''
|
||||||
formData.value.gender = data.gender || ''
|
formData.value.gender = getGenderLabel(r.gender)
|
||||||
formData.value.age = data.age || ''
|
formData.value.age = r.age ? `${r.age}岁` : ''
|
||||||
formData.value.educationStage = data.educationStage || ''
|
formData.value.educationStage = getEducationStageLabel(r.educationStage)
|
||||||
formData.value.province = data.province || ''
|
formData.value.province = r.province || ''
|
||||||
formData.value.city = data.city || ''
|
formData.value.city = r.city || ''
|
||||||
formData.value.district = data.district || ''
|
formData.value.district = r.district || ''
|
||||||
genderIndex.value = data.genderIndex ?? -1
|
|
||||||
ageIndex.value = data.ageIndex ?? -1
|
// 同步选择器索引
|
||||||
educationIndex.value = data.educationIndex ?? -1
|
genderIndex.value = r.gender === 1 ? 0 : r.gender === 2 ? 1 : -1
|
||||||
regionValue.value = data.regionValue || []
|
ageIndex.value = r.age ? r.age - 10 : -1
|
||||||
} catch (e) {
|
educationIndex.value = educationOptions.indexOf(getEducationStageLabel(r.educationStage))
|
||||||
console.error('还原表单数据失败:', e)
|
regionValue.value = [r.province || '', r.city || '', r.district || '']
|
||||||
}
|
|
||||||
|
showPendingPopup.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提交成功后清除缓存
|
* 放弃进行中的测评,重新开始
|
||||||
*/
|
*/
|
||||||
function clearFormStorage() {
|
function handleDismissPending() {
|
||||||
try {
|
pendingRecord.value = null
|
||||||
uni.removeStorageSync(STORAGE_KEY)
|
showPendingPopup.value = false
|
||||||
} catch (e) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听表单变化,自动保存
|
|
||||||
watch(formData, () => {
|
|
||||||
saveFormToStorage()
|
|
||||||
}, { deep: true })
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表单是否填写完整
|
* 表单是否填写完整
|
||||||
*/
|
*/
|
||||||
|
|
@ -162,6 +173,7 @@ const isFormComplete = computed(() => {
|
||||||
* 底部按钮文案
|
* 底部按钮文案
|
||||||
*/
|
*/
|
||||||
const payBtnText = computed(() => {
|
const payBtnText = computed(() => {
|
||||||
|
if (isContinueMode.value) return '继续测评'
|
||||||
return `支付¥${introData.value.price || 20}元开始测评`
|
return `支付¥${introData.value.price || 20}元开始测评`
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -262,6 +274,15 @@ function buildAssessmentInfo() {
|
||||||
/** 支付测评 */
|
/** 支付测评 */
|
||||||
async function handlePayAssessment() {
|
async function handlePayAssessment() {
|
||||||
if (!checkLogin()) return
|
if (!checkLogin()) return
|
||||||
|
|
||||||
|
// 继续测评模式:直接跳转到答题页
|
||||||
|
if (isContinueMode.value && pendingRecord.value) {
|
||||||
|
uni.redirectTo({
|
||||||
|
url: `/pages/assessment/questions/index?typeId=${typeId.value}&recordId=${pendingRecord.value.recordId}`
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (!validateForm()) return
|
if (!validateForm()) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -274,7 +295,6 @@ async function handlePayAssessment() {
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
clearFormStorage()
|
|
||||||
// 从 createOrder 返回中获取 assessmentRecordId
|
// 从 createOrder 返回中获取 assessmentRecordId
|
||||||
const recordId = result.assessmentRecordId || ''
|
const recordId = result.assessmentRecordId || ''
|
||||||
uni.redirectTo({
|
uni.redirectTo({
|
||||||
|
|
@ -342,7 +362,6 @@ async function submitInviteCode() {
|
||||||
|
|
||||||
if (orderRes && orderRes.code === 0 && orderRes.data) {
|
if (orderRes && orderRes.code === 0 && orderRes.data) {
|
||||||
closeInvitePopup()
|
closeInvitePopup()
|
||||||
clearFormStorage()
|
|
||||||
const recordId = orderRes.data.assessmentRecordId || ''
|
const recordId = orderRes.data.assessmentRecordId || ''
|
||||||
uni.redirectTo({
|
uni.redirectTo({
|
||||||
url: `/pages/assessment/questions/index?typeId=${typeId.value}&recordId=${recordId}`
|
url: `/pages/assessment/questions/index?typeId=${typeId.value}&recordId=${recordId}`
|
||||||
|
|
@ -365,20 +384,17 @@ onLoad((options) => {
|
||||||
typeName.value = decodeURIComponent(options.typeName || '')
|
typeName.value = decodeURIComponent(options.typeName || '')
|
||||||
userStore.restoreFromStorage()
|
userStore.restoreFromStorage()
|
||||||
|
|
||||||
// 还原本地缓存的表单数据
|
|
||||||
restoreFormFromStorage()
|
|
||||||
|
|
||||||
// 如果已登录且手机号为空,预填手机号
|
// 如果已登录且手机号为空,预填手机号
|
||||||
if (userStore.isLoggedIn && userStore.phone && !formData.value.phone) {
|
if (userStore.isLoggedIn && userStore.phone && !formData.value.phone) {
|
||||||
formData.value.phone = userStore.phone
|
formData.value.phone = userStore.phone
|
||||||
}
|
}
|
||||||
|
|
||||||
loadIntro()
|
loadIntro()
|
||||||
})
|
|
||||||
|
|
||||||
/** 页面卸载时保存 */
|
// 检查是否有进行中的测评记录
|
||||||
onUnload(() => {
|
if (userStore.isLoggedIn) {
|
||||||
saveFormToStorage()
|
checkPendingRecord()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -403,7 +419,7 @@ onUnload(() => {
|
||||||
<!-- 表单卡片 -->
|
<!-- 表单卡片 -->
|
||||||
<view class="form-card">
|
<view class="form-card">
|
||||||
<view class="form-tip">
|
<view class="form-tip">
|
||||||
正式测评前,请先填写您的基本信息
|
{{ isContinueMode ? '您有一份进行中的测评,信息已自动填充' : '正式测评前,请先填写您的基本信息' }}
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 姓名 -->
|
<!-- 姓名 -->
|
||||||
|
|
@ -416,6 +432,7 @@ onUnload(() => {
|
||||||
placeholder-class="input-placeholder"
|
placeholder-class="input-placeholder"
|
||||||
v-model="formData.name"
|
v-model="formData.name"
|
||||||
maxlength="20"
|
maxlength="20"
|
||||||
|
:disabled="isContinueMode"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
@ -430,6 +447,7 @@ onUnload(() => {
|
||||||
placeholder-class="input-placeholder"
|
placeholder-class="input-placeholder"
|
||||||
v-model="formData.phone"
|
v-model="formData.phone"
|
||||||
maxlength="11"
|
maxlength="11"
|
||||||
|
:disabled="isContinueMode"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
@ -437,7 +455,7 @@ onUnload(() => {
|
||||||
<!-- 性别 -->
|
<!-- 性别 -->
|
||||||
<view class="form-item">
|
<view class="form-item">
|
||||||
<view class="form-label"><text class="required">*</text>性别</view>
|
<view class="form-label"><text class="required">*</text>性别</view>
|
||||||
<picker mode="selector" :range="genderOptions" @change="onGenderChange">
|
<picker mode="selector" :range="genderOptions" @change="onGenderChange" :disabled="isContinueMode">
|
||||||
<view class="form-select-box">
|
<view class="form-select-box">
|
||||||
<text :class="formData.gender ? 'select-value' : 'select-placeholder'">
|
<text :class="formData.gender ? 'select-value' : 'select-placeholder'">
|
||||||
{{ formData.gender || '请选择' }}
|
{{ formData.gender || '请选择' }}
|
||||||
|
|
@ -450,7 +468,7 @@ onUnload(() => {
|
||||||
<!-- 年龄 -->
|
<!-- 年龄 -->
|
||||||
<view class="form-item">
|
<view class="form-item">
|
||||||
<view class="form-label"><text class="required">*</text>年龄</view>
|
<view class="form-label"><text class="required">*</text>年龄</view>
|
||||||
<picker mode="selector" :range="ageOptions" @change="onAgeChange">
|
<picker mode="selector" :range="ageOptions" @change="onAgeChange" :disabled="isContinueMode">
|
||||||
<view class="form-select-box">
|
<view class="form-select-box">
|
||||||
<text :class="formData.age ? 'select-value' : 'select-placeholder'">
|
<text :class="formData.age ? 'select-value' : 'select-placeholder'">
|
||||||
{{ formData.age || '请选择' }}
|
{{ formData.age || '请选择' }}
|
||||||
|
|
@ -463,7 +481,7 @@ onUnload(() => {
|
||||||
<!-- 学业阶段 -->
|
<!-- 学业阶段 -->
|
||||||
<view class="form-item">
|
<view class="form-item">
|
||||||
<view class="form-label"><text class="required">*</text>学业阶段</view>
|
<view class="form-label"><text class="required">*</text>学业阶段</view>
|
||||||
<picker mode="selector" :range="educationOptions" @change="onEducationChange">
|
<picker mode="selector" :range="educationOptions" @change="onEducationChange" :disabled="isContinueMode">
|
||||||
<view class="form-select-box">
|
<view class="form-select-box">
|
||||||
<text :class="formData.educationStage ? 'select-value' : 'select-placeholder'">
|
<text :class="formData.educationStage ? 'select-value' : 'select-placeholder'">
|
||||||
{{ formData.educationStage || '请选择' }}
|
{{ formData.educationStage || '请选择' }}
|
||||||
|
|
@ -476,7 +494,7 @@ onUnload(() => {
|
||||||
<!-- 所在城市 -->
|
<!-- 所在城市 -->
|
||||||
<view class="form-item form-item-last">
|
<view class="form-item form-item-last">
|
||||||
<view class="form-label"><text class="required">*</text>所在城市</view>
|
<view class="form-label"><text class="required">*</text>所在城市</view>
|
||||||
<picker mode="region" @change="onRegionChange">
|
<picker mode="region" @change="onRegionChange" :disabled="isContinueMode">
|
||||||
<view class="form-region-row">
|
<view class="form-region-row">
|
||||||
<view class="region-box">
|
<view class="region-box">
|
||||||
<text :class="formData.province ? 'select-value' : 'select-placeholder'">
|
<text :class="formData.province ? 'select-value' : 'select-placeholder'">
|
||||||
|
|
@ -503,10 +521,10 @@ onUnload(() => {
|
||||||
|
|
||||||
<!-- 底部按钮 -->
|
<!-- 底部按钮 -->
|
||||||
<view class="btn-group">
|
<view class="btn-group">
|
||||||
<view class="btn-invite" @click="openInvitePopup">
|
<view v-if="!isContinueMode" class="btn-invite" @click="openInvitePopup">
|
||||||
<text>邀请码免费测评</text>
|
<text>邀请码免费测评</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="btn-pay" @click="handlePayAssessment">
|
<view class="btn-pay" :class="{ 'btn-full': isContinueMode }" @click="handlePayAssessment">
|
||||||
<text>{{ payBtnText }}</text>
|
<text>{{ payBtnText }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
@ -537,6 +555,31 @@ onUnload(() => {
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<!-- 进行中测评弹窗 -->
|
||||||
|
<view v-if="showPendingPopup" class="popup-mask" @click="handleDismissPending">
|
||||||
|
<view class="popup-container pending-popup" @click.stop>
|
||||||
|
<view class="popup-header">
|
||||||
|
<text class="popup-title">发现进行中的测评</text>
|
||||||
|
</view>
|
||||||
|
<view class="popup-body">
|
||||||
|
<view class="pending-msg">
|
||||||
|
您有一份未完成的测评记录,是否继续?
|
||||||
|
</view>
|
||||||
|
<view class="pending-info">
|
||||||
|
<text>姓名:{{ pendingRecord?.name }}</text>
|
||||||
|
<text>手机号:{{ pendingRecord?.phone }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="pending-footer">
|
||||||
|
<view class="popup-btn-outline" @click="handleDismissPending">
|
||||||
|
<text>重新开始</text>
|
||||||
|
</view>
|
||||||
|
<view class="popup-btn" @click="handleContinuePending">
|
||||||
|
<text>继续测评</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -750,6 +793,10 @@ onUnload(() => {
|
||||||
&:active {
|
&:active {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.btn-full {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 弹窗通用 ==========
|
// ========== 弹窗通用 ==========
|
||||||
|
|
@ -855,6 +902,41 @@ onUnload(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========== 进行中测评弹窗 ==========
|
||||||
|
.pending-popup {
|
||||||
|
.pending-msg {
|
||||||
|
font-size: $font-size-md;
|
||||||
|
color: $text-color;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: $spacing-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pending-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $spacing-sm;
|
||||||
|
background-color: $bg-gray;
|
||||||
|
border-radius: $border-radius-md;
|
||||||
|
padding: $spacing-lg;
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
color: $text-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pending-footer {
|
||||||
|
display: flex;
|
||||||
|
gap: $spacing-md;
|
||||||
|
padding: 0 $spacing-lg $spacing-xl;
|
||||||
|
|
||||||
|
.popup-btn-outline,
|
||||||
|
.popup-btn {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ========== 邀请码输入 ==========
|
// ========== 邀请码输入 ==========
|
||||||
.invite-input {
|
.invite-input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user