feat(assessment): Add retest status for equal score detection
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
- 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
This commit is contained in:
parent
04b9fa8220
commit
f8a9aaf71f
|
|
@ -34,7 +34,8 @@ public class AssessmentRecordService : IAssessmentRecordService
|
|||
{ 3, "生成中" },
|
||||
{ 4, "已完成" },
|
||||
{ 5, "生成失败" },
|
||||
{ 6, "数据已就绪" }
|
||||
{ 6, "数据已就绪" },
|
||||
{ 7, "需重测" }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -495,6 +495,7 @@ function getStatusTagType(status: number): 'info' | 'primary' | 'warning' | 'suc
|
|||
case 4: return 'success'
|
||||
case 5: return 'danger'
|
||||
case 6: return 'primary'
|
||||
case 7: return 'warning'
|
||||
default: return 'info'
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Text.Json;
|
||||
using MiAssessment.Core.Exceptions;
|
||||
using MiAssessment.Core.Interfaces;
|
||||
using MiAssessment.Core.Models;
|
||||
using MiAssessment.Core.Services;
|
||||
|
|
@ -165,6 +166,13 @@ public class ReportQueueConsumer : BackgroundService
|
|||
await UpdateRecordStatusToFailedAsync(message.RecordId);
|
||||
}
|
||||
}
|
||||
catch (AllScoresEqualException asEx)
|
||||
{
|
||||
// 同分异常:不重试,直接设置状态为需重测(Status=7)
|
||||
_logger.LogWarning("检测到全同分情况,RecordId: {RecordId}, ScoreType: {ScoreType}, Message: {Message}",
|
||||
message.RecordId, asEx.ScoreType, asEx.Message);
|
||||
await UpdateRecordStatusToRetestAsync(message.RecordId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 报告生成失败,执行重试或死信逻辑
|
||||
|
|
@ -257,4 +265,41 @@ public class ReportQueueConsumer : BackgroundService
|
|||
_logger.LogError(ex, "更新测评记录状态为生成失败时发生异常,RecordId: {RecordId}", recordId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新测评记录状态为需重测(Status=7)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 当检测到八大智能8项全同分或40项细分维度全同分时调用,
|
||||
/// 不生成PDF,提示用户重新测评。
|
||||
/// </remarks>
|
||||
/// <param name="recordId">测评记录ID</param>
|
||||
private async Task UpdateRecordStatusToRetestAsync(long recordId)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<MiAssessmentDbContext>();
|
||||
|
||||
var record = await dbContext.AssessmentRecords
|
||||
.FirstOrDefaultAsync(r => r.Id == recordId);
|
||||
|
||||
if (record != null)
|
||||
{
|
||||
record.Status = 7;
|
||||
record.UpdateTime = DateTime.Now;
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
_logger.LogInformation("测评记录状态已更新为需重测,RecordId: {RecordId}", recordId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("更新状态失败,测评记录不存在,RecordId: {RecordId}", recordId);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "更新测评记录状态为需重测时发生异常,RecordId: {RecordId}", recordId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
namespace MiAssessment.Core.Exceptions;
|
||||
|
||||
/// <summary>
|
||||
/// 所有分数相同异常(八大智能全同分或40项细分全同分)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 当检测到八大智能8项全部同分或40项细分维度全部同分时抛出,
|
||||
/// 表示无法生成有效的差异化报告,需要用户重新测评。
|
||||
/// </remarks>
|
||||
public class AllScoresEqualException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// 同分类型:Intelligence=八大智能同分,Ability=细分维度同分
|
||||
/// </summary>
|
||||
public string ScoreType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="scoreType">同分类型</param>
|
||||
/// <param name="message">异常信息</param>
|
||||
public AllScoresEqualException(string scoreType, string message)
|
||||
: base(message)
|
||||
{
|
||||
ScoreType = scoreType;
|
||||
}
|
||||
}
|
||||
|
|
@ -119,6 +119,11 @@ public class AssessmentService : IAssessmentService
|
|||
{
|
||||
record.Message = "报告生成失败,请联系客服";
|
||||
}
|
||||
// 对需重测状态设置提示信息
|
||||
else if (record.Status == 7)
|
||||
{
|
||||
record.Message = "分析得出多个智能处于同一梯队,我们需要更细致的分析维度,接下来请您重新进行测评";
|
||||
}
|
||||
|
||||
_logger.LogDebug("查询报告状态成功,status: {Status}, isCompleted: {IsCompleted}", record.Status, record.IsCompleted);
|
||||
}
|
||||
|
|
@ -655,6 +660,7 @@ public class AssessmentService : IAssessmentService
|
|||
4 => "已完成",
|
||||
5 => "生成失败",
|
||||
6 => "报告生成中",
|
||||
7 => "需重测",
|
||||
_ => "未知"
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using MiAssessment.Core.Exceptions;
|
||||
using MiAssessment.Model.Data;
|
||||
using MiAssessment.Model.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
|
@ -60,6 +61,9 @@ public class ReportGenerationService
|
|||
_logger.LogDebug("父级汇总完成,recordId: {RecordId}, 新增父级数量: {Count}, 总数量: {Total}",
|
||||
recordId, parentScores.Count, categoryScores.Count);
|
||||
|
||||
// 步骤3.6:检测同分情况(八大智能全同分或细分维度全同分)
|
||||
CheckAllScoresEqual(categoryScores);
|
||||
|
||||
// 步骤4:按 CategoryType 分组排名
|
||||
var rankedScores = CalculateRanks(categoryScores);
|
||||
|
||||
|
|
@ -300,6 +304,39 @@ public class ReportGenerationService
|
|||
return parentScores;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检测同分情况:八大智能8项全同分或细分维度全同分
|
||||
/// </summary>
|
||||
/// <param name="categoryScores">所有分类得分(含叶子和父级)</param>
|
||||
/// <exception cref="AllScoresEqualException">当检测到全同分时抛出</exception>
|
||||
internal static void CheckAllScoresEqual(List<CategoryScore> categoryScores)
|
||||
{
|
||||
// CategoryType=1 为八大智能(父级汇总后的得分)
|
||||
var intelligenceScores = categoryScores
|
||||
.Where(s => s.CategoryType == 1)
|
||||
.Select(s => s.Percentage)
|
||||
.ToList();
|
||||
|
||||
if (intelligenceScores.Count >= 8 && intelligenceScores.Distinct().Count() == 1)
|
||||
{
|
||||
throw new AllScoresEqualException("Intelligence",
|
||||
$"八大智能8项得分全部相同({intelligenceScores.First()}%),无法生成差异化报告");
|
||||
}
|
||||
|
||||
// CategoryType=3 为细分能力维度
|
||||
var abilityScores = categoryScores
|
||||
.Where(s => s.CategoryType == 3)
|
||||
.Select(s => s.Percentage)
|
||||
.ToList();
|
||||
|
||||
if (abilityScores.Count >= 40 && abilityScores.Distinct().Count() == 1)
|
||||
{
|
||||
throw new AllScoresEqualException("Ability",
|
||||
$"40项细分维度得分全部相同({abilityScores.First()}%),无法生成差异化报告");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 分类得分计算结果
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ namespace MiAssessment.Model.Models.Assessment;
|
|||
public class ResultStatusDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 状态:0待支付 1待测评 2测评中 3生成中 4已完成 5生成失败
|
||||
/// 状态:0待支付 1待测评 2测评中 3生成中 4已完成 5生成失败 6数据已就绪 7需重测
|
||||
/// </summary>
|
||||
public int Status { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ const ASSESSMENT_STATUS = {
|
|||
GENERATING: 3, // 生成中
|
||||
COMPLETED: 4, // 已完成
|
||||
FAILED: 5, // 生成失败
|
||||
DATA_READY: 6 // 数据已就绪(PDF生成中)
|
||||
DATA_READY: 6, // 数据已就绪(PDF生成中)
|
||||
NEED_RETEST: 7 // 需重测(全同分)
|
||||
}
|
||||
|
||||
// 状态
|
||||
|
|
@ -46,7 +47,8 @@ function getStatusClass(status) {
|
|||
[ASSESSMENT_STATUS.GENERATING]: 'status-generating',
|
||||
[ASSESSMENT_STATUS.COMPLETED]: 'status-completed',
|
||||
[ASSESSMENT_STATUS.FAILED]: 'status-failed',
|
||||
[ASSESSMENT_STATUS.DATA_READY]: 'status-generating'
|
||||
[ASSESSMENT_STATUS.DATA_READY]: 'status-generating',
|
||||
[ASSESSMENT_STATUS.NEED_RETEST]: 'status-retest'
|
||||
}
|
||||
return classMap[status] || ''
|
||||
}
|
||||
|
|
@ -155,6 +157,14 @@ function viewResult(record) {
|
|||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 需重测 - 跳转到测评首页重新开始
|
||||
if (record.status === ASSESSMENT_STATUS.NEED_RETEST) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/assessment/info/index?typeId=${record.assessmentTypeId || 1}`
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -208,13 +218,19 @@ onMounted(() => {
|
|||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 卡片底部:已完成显示查看报告 -->
|
||||
<!-- 卡片底部:已完成显示查看报告,需重测显示重新测试 -->
|
||||
<view class="card-footer" v-if="record.status === ASSESSMENT_STATUS.COMPLETED || record.status === ASSESSMENT_STATUS.DATA_READY">
|
||||
<view class="view-btn">
|
||||
<text>查看报告</text>
|
||||
<view class="arrow-icon"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-footer" v-else-if="record.status === ASSESSMENT_STATUS.NEED_RETEST">
|
||||
<view class="view-btn retest-btn">
|
||||
<text>重新测试</text>
|
||||
<view class="arrow-icon"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 加载更多 -->
|
||||
|
|
@ -296,6 +312,18 @@ onMounted(() => {
|
|||
color: $success-color;
|
||||
background-color: rgba(82, 196, 26, 0.1);
|
||||
}
|
||||
|
||||
// 生成失败 - 红色
|
||||
&.status-failed {
|
||||
color: $error-color;
|
||||
background-color: rgba(255, 77, 79, 0.1);
|
||||
}
|
||||
|
||||
// 需重测 - 橙色
|
||||
&.status-retest {
|
||||
color: $warning-color;
|
||||
background-color: rgba(250, 173, 20, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -331,6 +359,15 @@ onMounted(() => {
|
|||
align-items: center;
|
||||
color: $primary-color;
|
||||
font-size: $font-size-md;
|
||||
|
||||
&.retest-btn {
|
||||
color: $warning-color;
|
||||
|
||||
.arrow-icon {
|
||||
border-right-color: $warning-color;
|
||||
border-bottom-color: $warning-color;
|
||||
}
|
||||
}
|
||||
|
||||
.arrow-icon {
|
||||
width: 12rpx;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
* - 显示提示文字
|
||||
* - 轮询查询报告生成状态(3秒间隔)
|
||||
* - 生成完成自动跳转结果页
|
||||
* - Status=7 需重测:显示提示和重新测试按钮
|
||||
*/
|
||||
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
|
|
@ -19,6 +20,7 @@ const userStore = useUserStore()
|
|||
|
||||
// 页面参数
|
||||
const recordId = ref('')
|
||||
const typeId = ref('')
|
||||
|
||||
// 轮询定时器
|
||||
let pollTimer = null
|
||||
|
|
@ -32,6 +34,10 @@ const MAX_POLL_COUNT = 100
|
|||
// 当前轮询次数
|
||||
const pollCount = ref(0)
|
||||
|
||||
// 是否需要重新测评(Status=7)
|
||||
const needRetest = ref(false)
|
||||
const retestMessage = ref('')
|
||||
|
||||
/**
|
||||
* 开始轮询查询状态
|
||||
*/
|
||||
|
|
@ -90,7 +96,7 @@ async function checkStatus() {
|
|||
if (res && res.code === 0 && res.data) {
|
||||
const status = res.data.status
|
||||
|
||||
// 状态:3-生成中 4-已完成 5-失败
|
||||
// 状态:3-生成中 4-已完成 5-失败 7-需重测
|
||||
if (status === 4) {
|
||||
// 生成完成,跳转结果页
|
||||
stopPolling()
|
||||
|
|
@ -100,6 +106,11 @@ async function checkStatus() {
|
|||
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()
|
||||
|
|
@ -115,7 +126,7 @@ async function checkStatus() {
|
|||
}
|
||||
})
|
||||
}
|
||||
// status === 3 继续轮询
|
||||
// status === 3 或 6 继续轮询
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('查询状态失败:', error)
|
||||
|
|
@ -123,11 +134,28 @@ async function checkStatus() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新测试
|
||||
*/
|
||||
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()
|
||||
|
|
@ -149,8 +177,17 @@ onUnmounted(() => {
|
|||
<!-- 导航栏 -->
|
||||
<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 class="loading-content">
|
||||
<view v-else class="loading-content">
|
||||
<!-- 加载图片 -->
|
||||
<image class="loading-image" src="/static/cepingzhong.png" mode="aspectFit" />
|
||||
|
||||
|
|
@ -160,6 +197,13 @@ onUnmounted(() => {
|
|||
<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>
|
||||
|
||||
|
|
@ -170,6 +214,8 @@ onUnmounted(() => {
|
|||
.assessment-loading-page {
|
||||
min-height: 100vh;
|
||||
background-color: $bg-white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.loading-content {
|
||||
|
|
@ -205,4 +251,64 @@ onUnmounted(() => {
|
|||
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>
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ async function handleSubmit() {
|
|||
|
||||
if (res && res.code === 0) {
|
||||
const resRecordId = res.data?.recordId || res.data?.id || recordId.value
|
||||
uni.redirectTo({ url: `/pages/assessment/loading/index?recordId=${resRecordId}` })
|
||||
uni.redirectTo({ url: `/pages/assessment/loading/index?recordId=${resRecordId}&typeId=${typeId.value}` })
|
||||
} else {
|
||||
uni.showToast({ title: res?.message || '提交失败,请重试', icon: 'none' })
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user