mi-assessment/uniapp/pages/assessment/loading/index.vue
zpc f8a9aaf71f
Some checks failed
continuous-integration/drone/push Build is failing
feat(assessment): Add retest status for equal score detection
- Add new assessment status 7 ("需重测") for cases where all scores are equal
- Create AllScoresEqualException to handle scenarios where 8 intelligences or 40 ability dimensions have identical scores
- Implement CheckAllScoresEqual validation in ReportGenerationService to detect and prevent invalid report generation
- Add UpdateRecordStatusToRetestAsync method in ReportQueueConsumer to handle retest status updates
- Update admin UI status tag mapping to display retest status with warning indicator
- Add user-friendly message for retest status in AssessmentService
- Update status description mappings across services to include new retest status
- Prevent PDF generation when all scores are equal, prompting users to retake the assessment
2026-03-31 15:08:23 +08:00

315 lines
6.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup>
/**
* 测评生成中页面
*
* 功能:
* - 显示加载动画
* - 显示提示文字
* - 轮询查询报告生成状态3秒间隔
* - 生成完成自动跳转结果页
* - Status=7 需重测:显示提示和重新测试按钮
*/
import { ref, onMounted, onUnmounted } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { useUserStore } from '@/store/user.js'
import { getResultStatus } from '@/api/assessment.js'
import Navbar from '@/components/Navbar/index.vue'
const userStore = useUserStore()
// 页面参数
const recordId = ref('')
const typeId = ref('')
// 轮询定时器
let pollTimer = null
// 轮询间隔(毫秒)
const POLL_INTERVAL = 3000
// 最大轮询次数(防止无限轮询)
const MAX_POLL_COUNT = 100
// 当前轮询次数
const pollCount = ref(0)
// 是否需要重新测评Status=7
const needRetest = ref(false)
const retestMessage = ref('')
/**
* 开始轮询查询状态
*/
function startPolling() {
// 清除已有定时器
stopPolling()
// 立即查询一次
checkStatus()
// 设置轮询定时器
pollTimer = setInterval(() => {
checkStatus()
}, POLL_INTERVAL)
}
/**
* 停止轮询
*/
function stopPolling() {
if (pollTimer) {
clearInterval(pollTimer)
pollTimer = null
}
}
/**
* 查询报告生成状态
*/
async function checkStatus() {
if (!recordId.value) {
console.error('缺少测评记录ID')
return
}
// 检查轮询次数
pollCount.value++
if (pollCount.value > MAX_POLL_COUNT) {
stopPolling()
uni.showModal({
title: '提示',
content: '报告生成时间较长,请稍后在"往期测评"中查看',
showCancel: false,
success: () => {
uni.switchTab({
url: '/pages/mine/index'
})
}
})
return
}
try {
const res = await getResultStatus(recordId.value)
if (res && res.code === 0 && res.data) {
const status = res.data.status
// 状态3-生成中 4-已完成 5-失败 7-需重测
if (status === 4) {
// 生成完成,跳转结果页
stopPolling()
// 携带 reportUrl 参数
const reportUrl = res.data.reportUrl || ''
uni.redirectTo({
url: `/pages/assessment/result/index?recordId=${recordId.value}&reportUrl=${encodeURIComponent(reportUrl)}`
})
} else if (status === 7) {
// 需重测:停止轮询,显示提示和重新测试按钮
stopPolling()
needRetest.value = true
retestMessage.value = res.data.message || '分析得出多个智能处于同一梯队,我们需要更细致的分析维度,接下来请您重新进行测评'
} else if (status === 5) {
// 生成失败
stopPolling()
uni.showModal({
title: '提示',
content: res.data.message || '报告生成失败,请联系客服',
showCancel: false,
success: () => {
uni.switchTab({
url: '/pages/index/index'
})
}
})
}
// status === 3 或 6 继续轮询
}
} catch (error) {
console.error('查询状态失败:', error)
// 网络错误不停止轮询,继续尝试
}
}
/**
* 重新测试
*/
function handleRetest() {
// 跳转到测评首页重新开始
if (typeId.value) {
uni.redirectTo({
url: `/pages/assessment/info/index?typeId=${typeId.value}`
})
} else {
uni.switchTab({
url: '/pages/index/index'
})
}
}
/**
* 页面加载
*/
onLoad((options) => {
recordId.value = options.recordId || ''
typeId.value = options.typeId || ''
// 恢复用户登录状态
userStore.restoreFromStorage()
// 开始轮询
startPolling()
})
/**
* 页面卸载时清理定时器
*/
onUnmounted(() => {
stopPolling()
})
</script>
<template>
<view class="assessment-loading-page">
<!-- 导航栏 -->
<Navbar title="多元智能测评" :showBack="true" />
<!-- 需重测提示 -->
<view v-if="needRetest" class="retest-content">
<image class="retest-image" src="/static/cepingzhong.png" mode="aspectFit" />
<view class="retest-text">
<text class="retest-title">{{ retestMessage }}</text>
</view>
</view>
<!-- 加载内容区域 -->
<view v-else class="loading-content">
<!-- 加载图片 -->
<image class="loading-image" src="/static/cepingzhong.png" mode="aspectFit" />
<!-- 提示文字 -->
<view class="loading-text">
<text class="loading-title">测评生成中,请耐心等待</text>
<text class="loading-tip">可在往期测评中查看测评结果</text>
</view>
</view>
<!-- 重新测试按钮 -->
<view v-if="needRetest" class="bottom-action">
<view class="retest-btn" @click="handleRetest">
<text>重新测试</text>
</view>
</view>
</view>
</template>
<style lang="scss" scoped>
@import '@/styles/variables.scss';
.assessment-loading-page {
min-height: 100vh;
background-color: $bg-white;
display: flex;
flex-direction: column;
}
.loading-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: calc(100vh - 200rpx);
padding: $spacing-xl;
}
// 加载图片
.loading-image {
width: 360rpx;
height: 360rpx;
margin-bottom: $spacing-xl;
}
// 提示文字
.loading-text {
text-align: center;
}
.loading-title {
display: block;
font-size: $font-size-lg;
color: $text-secondary;
margin-bottom: $spacing-sm;
}
.loading-tip {
display: block;
font-size: $font-size-md;
color: $text-placeholder;
}
// 需重测内容
.retest-content {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: $spacing-xl 64rpx;
}
.retest-image {
width: 360rpx;
height: 360rpx;
margin-bottom: $spacing-xl;
}
.retest-text {
text-align: center;
}
.retest-title {
display: block;
font-size: $font-size-lg;
color: $text-secondary;
line-height: 1.6;
}
// 底部操作栏
.bottom-action {
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: $spacing-lg $spacing-xl;
padding-bottom: calc(#{$spacing-lg} + env(safe-area-inset-bottom));
background-color: transparent;
z-index: 100;
}
// 重新测试按钮
.retest-btn {
width: 100%;
height: 88rpx;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #FF8A6B 0%, #FF6B6B 100%);
border-radius: $border-radius-round;
text {
font-size: $font-size-lg;
color: $text-white;
font-weight: $font-weight-medium;
}
&:active {
opacity: 0.85;
}
}
</style>