fix(assessment): 修复往期测评数据显示问题

- DTO新增Name和AssessmentTypeId字段,前端可显示测评人姓名
- 修正前端状态映射:1待测评 2测评中 3生成中 4已完成(与后端一致)
- 直接使用后端返回的statusText,避免前后端状态不同步
- 后端查询改用左连接,避免缺少关联数据时丢失记录
- 待测评/测评中状态点击可跳转继续答题
This commit is contained in:
zpc 2026-02-23 00:19:24 +08:00
parent 7a54c91154
commit 143a8fa5f2
3 changed files with 73 additions and 76 deletions

View File

@ -132,29 +132,39 @@ public class AssessmentService : IAssessmentService
// 获取总数 // 获取总数
var total = await query.CountAsync(); var total = await query.CountAsync();
// 分页查询 // 分页查询(使用左连接避免缺少关联数据时丢失记录)
var records = await query var records = await query
.OrderByDescending(r => r.CreateTime) .OrderByDescending(r => r.CreateTime)
.Skip((page - 1) * pageSize) .Skip((page - 1) * pageSize)
.Take(pageSize) .Take(pageSize)
.Join( .GroupJoin(
_dbContext.Orders.AsNoTracking(), _dbContext.Orders.AsNoTracking(),
r => r.OrderId, r => r.OrderId,
o => o.Id, o => o.Id,
(r, o) => new { Record = r, Order = o } (r, orders) => new { Record = r, Orders = orders }
) )
.Join( .SelectMany(
ro => ro.Orders.DefaultIfEmpty(),
(ro, o) => new { ro.Record, Order = o }
)
.GroupJoin(
_dbContext.AssessmentTypes.AsNoTracking(), _dbContext.AssessmentTypes.AsNoTracking(),
ro => ro.Record.AssessmentTypeId, ro => ro.Record.AssessmentTypeId,
at => at.Id, at => at.Id,
(ro, at) => new AssessmentHistoryDto (ro, types) => new { ro.Record, ro.Order, Types = types }
)
.SelectMany(
rot => rot.Types.DefaultIfEmpty(),
(rot, at) => new AssessmentHistoryDto
{ {
Id = ro.Record.Id, Id = rot.Record.Id,
OrderNo = ro.Order.OrderNo, OrderNo = rot.Order != null ? rot.Order.OrderNo : "",
AssessmentName = at.Name, AssessmentName = at != null ? at.Name : "多元智能测评",
Status = ro.Record.Status, Name = rot.Record.Name,
StatusText = GetStatusText(ro.Record.Status), AssessmentTypeId = rot.Record.AssessmentTypeId,
TestDate = ro.Record.CreateTime.ToString("yyyy-MM-dd") Status = rot.Record.Status,
StatusText = GetStatusText(rot.Record.Status),
TestDate = rot.Record.CreateTime.ToString("yyyy-MM-dd")
} }
) )
.ToListAsync(); .ToListAsync();

View File

@ -20,6 +20,16 @@ public class AssessmentHistoryDto
/// </summary> /// </summary>
public string AssessmentName { get; set; } = null!; public string AssessmentName { get; set; } = null!;
/// <summary>
/// 测评人姓名
/// </summary>
public string Name { get; set; } = null!;
/// <summary>
/// 测评类型ID
/// </summary>
public long AssessmentTypeId { get; set; }
/// <summary> /// <summary>
/// 状态1待测评 2测评中 3生成中 4已完成 /// 状态1待测评 2测评中 3生成中 4已完成
/// </summary> /// </summary>

View File

@ -14,11 +14,12 @@ import Loading from '@/components/Loading/index.vue'
const userStore = useUserStore() const userStore = useUserStore()
const { checkLogin } = useAuth() const { checkLogin } = useAuth()
// //
const ASSESSMENT_STATUS = { const ASSESSMENT_STATUS = {
GENERATING: 1, // PENDING: 1, //
COMPLETED: 2, // TESTING: 2, //
FAILED: 3 // GENERATING: 3, //
COMPLETED: 4 //
} }
// //
@ -32,44 +33,20 @@ const noMore = ref(false)
// //
const isEmpty = computed(() => !loading.value && historyList.value.length === 0) const isEmpty = computed(() => !loading.value && historyList.value.length === 0)
const hasMore = computed(() => historyList.value.length < total.value)
/**
* 获取测评状态文本
*/
function getStatusText(status) {
const statusMap = {
[ASSESSMENT_STATUS.GENERATING]: '生成中',
[ASSESSMENT_STATUS.COMPLETED]: '已完成',
[ASSESSMENT_STATUS.FAILED]: '生成失败'
}
return statusMap[status] || '未知状态'
}
/** /**
* 获取测评状态样式类 * 获取测评状态样式类
*/ */
function getStatusClass(status) { function getStatusClass(status) {
const classMap = { const classMap = {
[ASSESSMENT_STATUS.PENDING]: 'status-pending',
[ASSESSMENT_STATUS.TESTING]: 'status-testing',
[ASSESSMENT_STATUS.GENERATING]: 'status-generating', [ASSESSMENT_STATUS.GENERATING]: 'status-generating',
[ASSESSMENT_STATUS.COMPLETED]: 'status-completed', [ASSESSMENT_STATUS.COMPLETED]: 'status-completed'
[ASSESSMENT_STATUS.FAILED]: 'status-failed'
} }
return classMap[status] || '' return classMap[status] || ''
} }
/**
* 格式化日期
*/
function formatDate(dateStr) {
if (!dateStr) return ''
const date = new Date(dateStr)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
/** /**
* 加载测评历史列表 * 加载测评历史列表
*/ */
@ -142,6 +119,15 @@ onReachBottom(() => {
* 查看测评结果 * 查看测评结果
*/ */
function viewResult(record) { 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) { if (record.status === ASSESSMENT_STATUS.GENERATING) {
uni.showToast({ uni.showToast({
title: '报告生成中,请稍后查看', title: '报告生成中,请稍后查看',
@ -150,24 +136,13 @@ function viewResult(record) {
return return
} }
if (record.status === ASSESSMENT_STATUS.FAILED) { // / -
uni.showToast({ if (record.status === ASSESSMENT_STATUS.PENDING || record.status === ASSESSMENT_STATUS.TESTING) {
title: '报告生成失败,请联系客服', uni.navigateTo({
icon: 'none' url: `/pages/assessment/info/index?typeId=${record.assessmentTypeId || 1}`
}) })
return return
} }
uni.navigateTo({
url: `/pages/assessment/result/index?recordId=${record.id}`
})
}
/**
* 判断是否显示查看结果按钮
*/
function showViewResultBtn(status) {
return status === ASSESSMENT_STATUS.COMPLETED
} }
/** /**
@ -201,28 +176,28 @@ onMounted(() => {
:key="record.id" :key="record.id"
@click="viewResult(record)" @click="viewResult(record)"
> >
<!-- 卡片头部 --> <!-- 卡片头部测评名称 + 状态 -->
<view class="card-header"> <view class="card-header">
<view class="assessment-name">{{ record.assessmentName || '多元智能测评' }}</view> <view class="assessment-name">{{ record.assessmentName || '多元智能测评' }}</view>
<view class="assessment-status" :class="getStatusClass(record.status)"> <view class="assessment-status" :class="getStatusClass(record.status)">
{{ getStatusText(record.status) }} {{ record.statusText }}
</view> </view>
</view> </view>
<!-- 卡片内容 --> <!-- 卡片内容测评人 + 测评日期 -->
<view class="card-content"> <view class="card-content">
<view class="info-row"> <view class="info-row">
<text class="info-label">测评人</text> <text class="info-label">测评人</text>
<text class="info-value">{{ record.userName || '--' }}</text> <text class="info-value">{{ record.name || '--' }}</text>
</view> </view>
<view class="info-row"> <view class="info-row">
<text class="info-label">测评日期</text> <text class="info-label">测评日期</text>
<text class="info-value">{{ formatDate(record.createTime) }}</text> <text class="info-value">{{ record.testDate || '--' }}</text>
</view> </view>
</view> </view>
<!-- 卡片底部操作 --> <!-- 卡片底部已完成显示查看报告 -->
<view class="card-footer" v-if="showViewResultBtn(record.status)"> <view class="card-footer" v-if="record.status === ASSESSMENT_STATUS.COMPLETED">
<view class="view-btn"> <view class="view-btn">
<text>查看报告</text> <text>查看报告</text>
<view class="arrow-icon"></view> <view class="arrow-icon"></view>
@ -260,7 +235,6 @@ onMounted(() => {
padding-bottom: calc(#{$spacing-lg} + env(safe-area-inset-bottom)); padding-bottom: calc(#{$spacing-lg} + env(safe-area-inset-bottom));
} }
//
.history-list { .history-list {
.history-card { .history-card {
background-color: $bg-white; background-color: $bg-white;
@ -269,7 +243,6 @@ onMounted(() => {
overflow: hidden; overflow: hidden;
box-shadow: $shadow-sm; box-shadow: $shadow-sm;
//
.card-header { .card-header {
display: flex; display: flex;
align-items: center; align-items: center;
@ -288,10 +261,16 @@ onMounted(() => {
padding: 4rpx 16rpx; padding: 4rpx 16rpx;
border-radius: $border-radius-sm; border-radius: $border-radius-sm;
// - 绿 // -
&.status-completed { &.status-pending {
color: $success-color; color: $warning-color;
background-color: rgba(82, 196, 26, 0.1); background-color: rgba(250, 173, 20, 0.1);
}
// -
&.status-testing {
color: $primary-color;
background-color: rgba(74, 144, 226, 0.1);
} }
// - // -
@ -300,15 +279,14 @@ onMounted(() => {
background-color: rgba(74, 144, 226, 0.1); background-color: rgba(74, 144, 226, 0.1);
} }
// - // - 绿
&.status-failed { &.status-completed {
color: $error-color; color: $success-color;
background-color: rgba(255, 77, 79, 0.1); background-color: rgba(82, 196, 26, 0.1);
} }
} }
} }
//
.card-content { .card-content {
padding: $spacing-md $spacing-lg; padding: $spacing-md $spacing-lg;
@ -330,7 +308,6 @@ onMounted(() => {
} }
} }
//
.card-footer { .card-footer {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;