|
@@ -48,6 +48,9 @@
|
|
|
<!-- Completed 阶段:直接渲染报告 -->
|
|
<!-- Completed 阶段:直接渲染报告 -->
|
|
|
<div v-else class="report-stage">
|
|
<div v-else class="report-stage">
|
|
|
<div class="report-scroll">
|
|
<div class="report-scroll">
|
|
|
|
|
+ <div v-if="reportError" class="report-error">
|
|
|
|
|
+ {{ reportError }}
|
|
|
|
|
+ </div>
|
|
|
<OverallReport
|
|
<OverallReport
|
|
|
:evaluation="displayEvaluation"
|
|
:evaluation="displayEvaluation"
|
|
|
:role="mockRole"
|
|
:role="mockRole"
|
|
@@ -155,9 +158,8 @@ const mockEvaluation: OverallEvaluation = {
|
|
|
audioDuration: 4, score: 88,
|
|
audioDuration: 4, score: 88,
|
|
|
pronunciation: { accuracy: 90, intonation: 85, stress: 82, fluency: 88 },
|
|
pronunciation: { accuracy: 90, intonation: 85, stress: 82, fluency: 88 },
|
|
|
feedback: {
|
|
feedback: {
|
|
|
- highlights: ['Good pronunciation of "pandas"', 'Natural intonation'],
|
|
|
|
|
- corrections: [],
|
|
|
|
|
- suggestions: ['Try: "I really love pandas because they\'re incredibly cute!"'],
|
|
|
|
|
|
|
+ comment: 'Good pronunciation of "pandas" with natural intonation.',
|
|
|
|
|
+ betterExpression: 'I really love pandas because they are incredibly cute!',
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
@@ -171,9 +173,8 @@ const mockEvaluation: OverallEvaluation = {
|
|
|
audioDuration: 3, score: 92,
|
|
audioDuration: 3, score: 92,
|
|
|
pronunciation: { accuracy: 95, intonation: 90, stress: 88, fluency: 92 },
|
|
pronunciation: { accuracy: 95, intonation: 90, stress: 88, fluency: 92 },
|
|
|
feedback: {
|
|
feedback: {
|
|
|
- highlights: ['Excellent fluency', 'Clear past tense usage'],
|
|
|
|
|
- corrections: [],
|
|
|
|
|
- suggestions: ['Add more details: "I visited the Beijing Zoo last month and saw giant pandas there."'],
|
|
|
|
|
|
|
+ comment: 'Excellent fluency and clear past tense usage.',
|
|
|
|
|
+ betterExpression: 'I visited the Beijing Zoo last month and saw giant pandas there.',
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
@@ -187,19 +188,20 @@ const mockEvaluation: OverallEvaluation = {
|
|
|
audioDuration: 3, score: 78,
|
|
audioDuration: 3, score: 78,
|
|
|
pronunciation: { accuracy: 80, intonation: 75, stress: 76, fluency: 82 },
|
|
pronunciation: { accuracy: 80, intonation: 75, stress: 76, fluency: 82 },
|
|
|
feedback: {
|
|
feedback: {
|
|
|
- highlights: ['Correct answer'],
|
|
|
|
|
- corrections: [{ original: 'like to eat', corrected: 'mainly feed on', explanation: '"feed on" is more natural for describing animal diets' }],
|
|
|
|
|
- suggestions: ['Expand: "Pandas mainly feed on bamboo, but they also eat fruits and vegetables."'],
|
|
|
|
|
|
|
+ comment: 'Correct answer. Try using a more natural phrase for animal diets.',
|
|
|
|
|
+ betterExpression: 'Pandas mainly feed on bamboo, but they also eat fruits and vegetables.',
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
],
|
|
],
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const realEvaluation = ref<OverallEvaluation | null>(null)
|
|
const realEvaluation = ref<OverallEvaluation | null>(null)
|
|
|
|
|
+const reportStatus = ref<DialogueReport['status'] | null>(null)
|
|
|
|
|
+const reportError = ref('')
|
|
|
|
|
|
|
|
const displayEvaluation = computed<OverallEvaluation>(() => {
|
|
const displayEvaluation = computed<OverallEvaluation>(() => {
|
|
|
const real = realEvaluation.value
|
|
const real = realEvaluation.value
|
|
|
- if (real && real.sentenceEvaluations.length > 0) return real
|
|
|
|
|
|
|
+ if (real) return real
|
|
|
return mockEvaluation
|
|
return mockEvaluation
|
|
|
})
|
|
})
|
|
|
|
|
|
|
@@ -235,13 +237,19 @@ async function startDialogue() {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function handleDialogueComplete(report: DialogueReport | null) {
|
|
function handleDialogueComplete(report: DialogueReport | null) {
|
|
|
|
|
+ reportStatus.value = report?.status ?? null
|
|
|
realEvaluation.value = report?.evaluation ?? null
|
|
realEvaluation.value = report?.evaluation ?? null
|
|
|
|
|
+ if (report?.status === 'failed') reportError.value = '报告生成失败,部分语音评分未完成。'
|
|
|
|
|
+ else if (report?.status === 'incomplete') reportError.value = '本次练习没有足够的有效回答生成报告。'
|
|
|
|
|
+ else reportError.value = ''
|
|
|
dialogueState.value = 'completed'
|
|
dialogueState.value = 'completed'
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function resetPreview() {
|
|
function resetPreview() {
|
|
|
dialogueState.value = 'ready'
|
|
dialogueState.value = 'ready'
|
|
|
realEvaluation.value = null
|
|
realEvaluation.value = null
|
|
|
|
|
+ reportStatus.value = null
|
|
|
|
|
+ reportError.value = ''
|
|
|
preparedSession.value = null
|
|
preparedSession.value = null
|
|
|
sessionError.value = null
|
|
sessionError.value = null
|
|
|
sessionCreating.value = false
|
|
sessionCreating.value = false
|
|
@@ -410,5 +418,16 @@ onUnmounted(() => { speakingStore.setPreviewState('ready') })
|
|
|
background: #e5e7eb;
|
|
background: #e5e7eb;
|
|
|
margin: 0;
|
|
margin: 0;
|
|
|
}
|
|
}
|
|
|
|
|
+.report-error {
|
|
|
|
|
+ max-width: 448px;
|
|
|
|
|
+ margin: 0 auto 12px;
|
|
|
|
|
+ padding: 10px 12px;
|
|
|
|
|
+ border: 1px solid #fed7aa;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ background: #fff7ed;
|
|
|
|
|
+ color: #c2410c;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ line-height: 1.5;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
</style>
|
|
</style>
|