From bed1cc47cdd82ba7b1ff58662d50472e8709d6b2 Mon Sep 17 00:00:00 2001 From: chenyuan Date: Thu, 16 Jul 2026 16:59:22 +0800 Subject: [PATCH] fix: map flat AI training evaluation payload --- src/views/components/TrainingAiEvaluation.vue | 32 +++++++++++++++---- tests/ai-training-evaluation.static.test.cjs | 4 +++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/views/components/TrainingAiEvaluation.vue b/src/views/components/TrainingAiEvaluation.vue index ee21315..a8041d9 100644 --- a/src/views/components/TrainingAiEvaluation.vue +++ b/src/views/components/TrainingAiEvaluation.vue @@ -78,10 +78,11 @@ const help = computed(() => normalizeOperation(evaluation.value.help || evaluati const assessment = computed(() => normalizeOperation(evaluation.value.assessment || evaluation.value.assessmentEvaluation, evaluation.value, "assessment")); const helpStatus = computed(() => help.value.status); const assessmentStatus = computed(() => assessment.value.status); -const helpReport = computed(() => asText(help.value.report || help.value.content || help.value.suggestion)); -const assessmentReport = computed(() => asText(assessment.value.report || assessment.value.content || assessment.value.feedback)); -const score = computed(() => assessment.value.score ?? evaluation.value.score ?? null); -const scoreCriteria = computed(() => normalizeCriteria(assessment.value.scoreCriteria || evaluation.value.scoreCriteria)); +const helpReport = computed(() => formatReport(help.value.report || help.value.content || help.value.suggestion)); +const assessmentReport = computed(() => formatReport(assessment.value.report || assessment.value.content || assessment.value.feedback)); +const assessmentReportData = computed(() => safeParseJson(evaluation.value.assessmentReportJson)); +const score = computed(() => evaluation.value.assessmentScore ?? assessment.value.score ?? assessmentReportData.value?.score ?? evaluation.value.score ?? null); +const scoreCriteria = computed(() => normalizeCriteria(assessmentReportData.value?.criteria || assessment.value.scoreCriteria || evaluation.value.scoreCriteria)); const isHelpDisabled = computed(() => !props.hasAnyAnswer || helpLoading.value || isTerminal(helpStatus.value)); const isAssessmentDisabled = computed(() => !props.hasAnyAnswer || assessmentLoading.value || isTerminal(assessmentStatus.value)); const helpActionLabel = computed(() => actionLabel(helpStatus.value, "生成助学建议", helpLoading.value)); @@ -175,10 +176,11 @@ function setLocalStatus(type, status) { function normalizeOperation(operation, root, type) { const value = operation && typeof operation === "object" ? operation : {}; const prefix = type === "help" ? "help" : "assessment"; + const flatReportKey = type === "help" ? "helpReportJson" : "assessmentReportJson"; return { ...value, status: String(value.status || root?.[`${prefix}Status`] || "PENDING").toUpperCase(), - report: value.report || root?.[`${prefix}Report`] || "", + report: value.report || root?.[flatReportKey] || root?.[`${prefix}Report`] || "", scoreCriteria: value.scoreCriteria || root?.scoreCriteria || [], }; } @@ -195,9 +197,25 @@ function normalizeCriteria(value) { }); } -function asText(value) { +function formatReport(value) { if (value == null) return ""; - return typeof value === "string" ? value : JSON.stringify(value, null, 2); + const parsed = typeof value === "string" ? safeParseJson(value) : value; + if (parsed == null) return typeof value === "string" ? value : ""; + try { + return JSON.stringify(parsed, null, 2); + } catch (error) { + return String(value); + } +} + +function safeParseJson(value) { + if (typeof value !== "string" || !value.trim()) return null; + try { + const parsed = JSON.parse(value); + return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null; + } catch (error) { + return null; + } } function isTerminal(status) { diff --git a/tests/ai-training-evaluation.static.test.cjs b/tests/ai-training-evaluation.static.test.cjs index 50712bb..3bb8cf6 100644 --- a/tests/ai-training-evaluation.static.test.cjs +++ b/tests/ai-training-evaluation.static.test.cjs @@ -20,4 +20,8 @@ assert(/!props\.hasAnyAnswer/.test(component), "AI actions should disable when n assert(/proxy\?\.\$modal\?\.confirm/.test(component), "assessment should request confirmation through the modal proxy"); assert(!/v-html/.test(component), "AI reports must be rendered as interpolated text, never v-html"); assert(/scoreCriteria/.test(component), "assessment should display score criteria"); +assert(/helpReportJson/.test(component) && /assessmentReportJson/.test(component), "flat backend report JSON fields should be mapped for display"); +assert(/assessmentScore/.test(component), "flat backend assessmentScore should be mapped to the displayed score"); +assert(/safeParseJson/.test(component), "flat report JSON should be parsed defensively"); +assert(/safeParseJson\([^)]*assessmentReportJson[^)]*\)[\s\S]*criteria|criteria[\s\S]*safeParseJson\([^)]*assessmentReportJson[^)]*\)/.test(component), "score criteria should be read from parsed assessmentReportJson"); assert(/retry/.test(component) || /重试/.test(component), "failed AI operations should expose a retry action");