WordPronunciationDisplay.vue 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. <template>
  2. <div v-if="words.length" class="word-pronunciation-display">
  3. <span
  4. v-for="(w, i) in words"
  5. :key="i"
  6. class="wpd-word"
  7. :class="`wpd-${classFor(w)}`"
  8. :title="`${w.word} · ${w.errorType} · ${Math.round(w.accuracyScore)}`"
  9. >{{ w.word }}</span>
  10. </div>
  11. </template>
  12. <script lang="ts" setup>
  13. import type { WordAnalysisItem } from '@/types/englishSpeaking'
  14. interface Props {
  15. words: WordAnalysisItem[]
  16. }
  17. defineProps<Props>()
  18. // 判定规则:
  19. // - Omission → missed(灰)
  20. // - Mispronunciation / Insertion → wrong(红)
  21. // - error_type=None 时按 accuracy_score 分层:
  22. // < 60 → wrong(红)
  23. // 60-79 → warning(橙)
  24. // ≥ 80 → correct(绿)
  25. function classFor(w: WordAnalysisItem): 'correct' | 'warning' | 'wrong' | 'missed' | 'ignored' {
  26. if (w.errorType === 'Omission') return 'missed'
  27. if (w.errorType === 'Mispronunciation' || w.errorType === 'Insertion') return 'wrong'
  28. if (w.errorType !== 'None') return 'ignored'
  29. const acc = w.accuracyScore
  30. if (acc < 60) return 'wrong'
  31. if (acc < 80) return 'warning'
  32. return 'correct'
  33. }
  34. </script>
  35. <style lang="scss" scoped>
  36. .word-pronunciation-display {
  37. font-size: 12px;
  38. color: #1f2937;
  39. line-height: 2;
  40. word-wrap: break-word;
  41. }
  42. .wpd-word {
  43. display: inline-block;
  44. margin-right: 8px;
  45. border-bottom: 2px solid transparent;
  46. padding-bottom: 1px;
  47. }
  48. .wpd-correct { border-bottom-color: #16a34a; }
  49. .wpd-warning { border-bottom-color: #f59e0b; }
  50. .wpd-wrong { border-bottom-color: #ef4444; }
  51. .wpd-missed { border-bottom-color: #9ca3af; }
  52. .wpd-ignored { border-bottom-color: transparent; }
  53. </style>