mi-assessment/uniapp/pages/assessment/history/index.vue
zpc 143a8fa5f2 fix(assessment): 修复往期测评数据显示问题
- DTO新增Name和AssessmentTypeId字段,前端可显示测评人姓名
- 修正前端状态映射:1待测评 2测评中 3生成中 4已完成(与后端一致)
- 直接使用后端返回的statusText,避免前后端状态不同步
- 后端查询改用左连接,避免缺少关联数据时丢失记录
- 待测评/测评中状态点击可跳转继续答题
2026-02-23 00:19:24 +08:00

340 lines
8.1 KiB
Vue

<script setup>
/**
* 往期测评页面
* 展示用户的历史测评记录
*/
import { ref, computed, onMounted } from 'vue'
import { onShow, onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app'
import { useUserStore } from '@/store/user.js'
import { useAuth } from '@/composables/useAuth.js'
import { getHistoryList } from '@/api/assessment.js'
import Empty from '@/components/Empty/index.vue'
import Loading from '@/components/Loading/index.vue'
const userStore = useUserStore()
const { checkLogin } = useAuth()
// 测评状态常量(与后端一致)
const ASSESSMENT_STATUS = {
PENDING: 1, // 待测评
TESTING: 2, // 测评中
GENERATING: 3, // 生成中
COMPLETED: 4 // 已完成
}
// 状态
const loading = ref(false)
const refreshing = ref(false)
const historyList = ref([])
const page = ref(1)
const pageSize = ref(10)
const total = ref(0)
const noMore = ref(false)
// 计算属性
const isEmpty = computed(() => !loading.value && historyList.value.length === 0)
/**
* 获取测评状态样式类
*/
function getStatusClass(status) {
const classMap = {
[ASSESSMENT_STATUS.PENDING]: 'status-pending',
[ASSESSMENT_STATUS.TESTING]: 'status-testing',
[ASSESSMENT_STATUS.GENERATING]: 'status-generating',
[ASSESSMENT_STATUS.COMPLETED]: 'status-completed'
}
return classMap[status] || ''
}
/**
* 加载测评历史列表
*/
async function loadHistoryList(isRefresh = false) {
if (loading.value) return
if (isRefresh) {
page.value = 1
noMore.value = false
}
loading.value = true
try {
const res = await getHistoryList({
page: page.value,
pageSize: pageSize.value
})
if (res.code === 0 && res.data) {
const list = res.data.list || []
total.value = res.data.total || 0
if (isRefresh) {
historyList.value = list
} else {
historyList.value = [...historyList.value, ...list]
}
// 判断是否还有更多
noMore.value = historyList.value.length >= total.value
} else {
uni.showToast({
title: res.message || '获取测评记录失败',
icon: 'none'
})
}
} catch (error) {
console.error('获取测评历史失败:', error)
uni.showToast({
title: '网络错误,请重试',
icon: 'none'
})
} finally {
loading.value = false
refreshing.value = false
uni.stopPullDownRefresh()
}
}
/**
* 下拉刷新
*/
onPullDownRefresh(() => {
refreshing.value = true
loadHistoryList(true)
})
/**
* 上拉加载更多
*/
onReachBottom(() => {
if (!noMore.value && !loading.value) {
page.value++
loadHistoryList()
}
})
/**
* 查看测评结果
*/
function viewResult(record) {
// 已完成 - 查看报告
if (record.status === ASSESSMENT_STATUS.COMPLETED) {
uni.navigateTo({
url: `/pages/assessment/result/index?recordId=${record.id}`
})
return
}
// 生成中 - 提示等待
if (record.status === ASSESSMENT_STATUS.GENERATING) {
uni.showToast({
title: '报告生成中,请稍后查看',
icon: 'none'
})
return
}
// 待测评/测评中 - 跳转到答题页继续
if (record.status === ASSESSMENT_STATUS.PENDING || record.status === ASSESSMENT_STATUS.TESTING) {
uni.navigateTo({
url: `/pages/assessment/info/index?typeId=${record.assessmentTypeId || 1}`
})
return
}
}
/**
* 页面显示时检查登录状态并加载数据
*/
onShow(() => {
userStore.restoreFromStorage()
if (checkLogin()) {
loadHistoryList(true)
}
})
/**
* 页面加载
*/
onMounted(() => {
userStore.restoreFromStorage()
})
</script>
<template>
<view class="history-page">
<!-- 页面加载中 -->
<Loading type="page" :loading="loading && historyList.length === 0" />
<!-- 测评记录列表 -->
<view class="history-list" v-if="!isEmpty">
<view
class="history-card"
v-for="record in historyList"
:key="record.id"
@click="viewResult(record)"
>
<!-- 卡片头部:测评名称 + 状态 -->
<view class="card-header">
<view class="assessment-name">{{ record.assessmentName || '多元智能测评' }}</view>
<view class="assessment-status" :class="getStatusClass(record.status)">
{{ record.statusText }}
</view>
</view>
<!-- 卡片内容:测评人 + 测评日期 -->
<view class="card-content">
<view class="info-row">
<text class="info-label">测评人</text>
<text class="info-value">{{ record.name || '--' }}</text>
</view>
<view class="info-row">
<text class="info-label">测评日期</text>
<text class="info-value">{{ record.testDate || '--' }}</text>
</view>
</view>
<!-- 卡片底部:已完成显示查看报告 -->
<view class="card-footer" v-if="record.status === ASSESSMENT_STATUS.COMPLETED">
<view class="view-btn">
<text>查看报告</text>
<view class="arrow-icon"></view>
</view>
</view>
</view>
<!-- 加载更多 -->
<Loading
type="more"
:loading="loading && historyList.length > 0"
:noMore="noMore"
noMoreText="没有更多测评记录了"
/>
</view>
<!-- 空状态 -->
<Empty
v-if="isEmpty"
text="暂无测评记录"
:showButton="true"
buttonText="去测评"
buttonUrl="/pages/index/index"
/>
</view>
</template>
<style lang="scss" scoped>
@import '@/styles/variables.scss';
.history-page {
min-height: 100vh;
background-color: $bg-color;
padding: $spacing-lg;
padding-bottom: calc(#{$spacing-lg} + env(safe-area-inset-bottom));
}
.history-list {
.history-card {
background-color: $bg-white;
border-radius: $border-radius-lg;
margin-bottom: $spacing-lg;
overflow: hidden;
box-shadow: $shadow-sm;
.card-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: $spacing-md $spacing-lg;
border-bottom: 1rpx solid $border-light;
.assessment-name {
font-size: $font-size-lg;
font-weight: $font-weight-medium;
color: $text-color;
}
.assessment-status {
font-size: $font-size-sm;
padding: 4rpx 16rpx;
border-radius: $border-radius-sm;
// 待测评 - 橙色
&.status-pending {
color: $warning-color;
background-color: rgba(250, 173, 20, 0.1);
}
// 测评中 - 蓝色
&.status-testing {
color: $primary-color;
background-color: rgba(74, 144, 226, 0.1);
}
// 生成中 - 蓝色
&.status-generating {
color: $primary-color;
background-color: rgba(74, 144, 226, 0.1);
}
// 已完成 - 绿色
&.status-completed {
color: $success-color;
background-color: rgba(82, 196, 26, 0.1);
}
}
}
.card-content {
padding: $spacing-md $spacing-lg;
.info-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: $spacing-xs 0;
.info-label {
font-size: $font-size-md;
color: $text-secondary;
}
.info-value {
font-size: $font-size-md;
color: $text-color;
}
}
}
.card-footer {
display: flex;
justify-content: flex-end;
padding: $spacing-md $spacing-lg;
border-top: 1rpx solid $border-light;
.view-btn {
display: flex;
align-items: center;
color: $primary-color;
font-size: $font-size-md;
.arrow-icon {
width: 12rpx;
height: 12rpx;
border-right: 3rpx solid $primary-color;
border-bottom: 3rpx solid $primary-color;
transform: rotate(-45deg);
margin-left: 8rpx;
}
&:active {
opacity: 0.7;
}
}
}
}
}
</style>