- DTO新增Name和AssessmentTypeId字段,前端可显示测评人姓名 - 修正前端状态映射:1待测评 2测评中 3生成中 4已完成(与后端一致) - 直接使用后端返回的statusText,避免前后端状态不同步 - 后端查询改用左连接,避免缺少关联数据时丢失记录 - 待测评/测评中状态点击可跳转继续答题
340 lines
8.1 KiB
Vue
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>
|