Просмотр исходного кода

feat(english-speaking): 结果页真实报告透传,mock 作为 fallback

DialogueChatView 在 complete 事件里带回 engine.getReport() 的结果(或 null),
TopicDiscussionPreview 优先展示真实 evaluation,无句子评语时回落 mock。
这样真实模式下 contentFeedback 可以沿"adaptReport → OverallEvaluation
→ OverallReport/DetailedReport → SentenceCard"的链路在结果页显示。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jimmylee 2 недель назад
Родитель
Сommit
a3713762a4

+ 15 - 6
src/views/Editor/EnglishSpeaking/preview/DialogueChatView.vue

@@ -480,7 +480,7 @@
 <script lang="ts" setup>
 import { ref, computed, watch, onMounted, onUnmounted, nextTick, h, defineComponent } from 'vue'
 import type { PropType } from 'vue'
-import type { PreviewChatMessage, BadgeAchievement } from '@/types/englishSpeaking'
+import type { PreviewChatMessage, BadgeAchievement, DialogueReport } from '@/types/englishSpeaking'
 import { useDialogueEngine } from '../composables/useDialogueEngine'
 import { useAudioRecorder } from '../composables/useAudioRecorder'
 
@@ -510,7 +510,7 @@ const props = withDefaults(defineProps<Props>(), {
   showChineseText: false,
 })
 
-const emit = defineEmits<{ complete: [] }>()
+const emit = defineEmits<{ complete: [report: DialogueReport | null] }>()
 
 // ─────────────────────────────────────────────
 // Config
@@ -811,9 +811,18 @@ function practiceThisWord() {
   handleStartRecording()
 }
 
-function handleExitConfirm() {
+async function handleExitConfirm() {
   showExitConfirm.value = false
-  emit('complete')
+  emit('complete', await fetchReportSafe())
+}
+
+async function fetchReportSafe(): Promise<DialogueReport | null> {
+  try {
+    return await engine.getReport()
+  } catch (err) {
+    console.warn('[speaking] getReport failed:', err)
+    return null
+  }
 }
 
 function handleRestart() {
@@ -918,8 +927,8 @@ watch(
 // 对话完成 → 通知父组件
 watch(
   () => engine.isComplete.value,
-  (complete) => {
-    if (complete) emit('complete')
+  async (complete) => {
+    if (complete) emit('complete', await fetchReportSafe())
   },
 )
 

+ 15 - 5
src/views/Editor/EnglishSpeaking/preview/TopicDiscussionPreview.vue

@@ -45,14 +45,14 @@
     <div v-else class="report-stage">
       <div class="report-scroll">
         <OverallReport
-          :evaluation="mockEvaluation"
+          :evaluation="displayEvaluation"
           :role="mockRole"
           :scoreDisplayMode="'numeric'"
           @restart="resetPreview"
           @complete="resetPreview"
         />
         <div class="report-divider" />
-        <DetailedReport :sentenceEvaluations="mockEvaluation.sentenceEvaluations" />
+        <DetailedReport :sentenceEvaluations="displayEvaluation.sentenceEvaluations" />
       </div>
     </div>
 
@@ -60,8 +60,8 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, watch, onMounted, onUnmounted } from 'vue'
-import type { OverallEvaluation, PreviewAIRole, PreviewDialogueState } from '@/types/englishSpeaking'
+import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
+import type { DialogueReport, OverallEvaluation, PreviewAIRole, PreviewDialogueState } from '@/types/englishSpeaking'
 import { useSpeakingStore } from '@/store/speaking'
 import { getSpeakingConfig } from '@/services/speaking'
 
@@ -187,16 +187,26 @@ const mockEvaluation: OverallEvaluation = {
   ],
 }
 
+const realEvaluation = ref<OverallEvaluation | null>(null)
+
+const displayEvaluation = computed<OverallEvaluation>(() => {
+  const real = realEvaluation.value
+  if (real && real.sentenceEvaluations.length > 0) return real
+  return mockEvaluation
+})
+
 function startDialogue() {
   dialogueState.value = 'chatting'
 }
 
-function handleDialogueComplete() {
+function handleDialogueComplete(report: DialogueReport | null) {
+  realEvaluation.value = report?.evaluation ?? null
   dialogueState.value = 'completed'
 }
 
 function resetPreview() {
   dialogueState.value = 'ready'
+  realEvaluation.value = null
 }
 
 // ── Sync with speakingStore (让 CanvasTool 可以驱动"重置预览") ──