102 lines
3.5 KiB
Vue
102 lines
3.5 KiB
Vue
<template>
|
||
<div class="wrap">
|
||
<el-card>
|
||
<template #header>
|
||
<div class="h">
|
||
<div class="title">复习模式</div>
|
||
<el-select v-model="mode" style="width: 220px" @change="loadOne">
|
||
<el-option label="听音拼写" value="spelling" />
|
||
<el-option label="英译中" value="en2cn" />
|
||
<el-option label="中译英" value="cn2en" />
|
||
</el-select>
|
||
</div>
|
||
</template>
|
||
|
||
<el-empty v-if="!record" description="暂无可复习的单词" />
|
||
|
||
<div v-else>
|
||
<el-alert v-if="modeHint" type="info" :title="modeHint" show-icon style="margin-bottom:12px" />
|
||
|
||
<el-card shadow="never" style="margin-bottom:12px">
|
||
<template v-if="mode === 'spelling'">
|
||
<el-button @click="play">播放读音(uk)</el-button>
|
||
</template>
|
||
<template v-else-if="mode === 'en2cn'">
|
||
<div class="q">{{ record.word?.word }}</div>
|
||
</template>
|
||
<template v-else>
|
||
<div class="q">{{ record.word?.definition }}</div>
|
||
</template>
|
||
</el-card>
|
||
|
||
<el-input v-model="answer" placeholder="输入答案并回车" @keyup.enter="submit" />
|
||
<div style="margin-top:12px; display:flex; gap:12px">
|
||
<el-button type="primary" :loading="loading" @click="submit">提交</el-button>
|
||
<el-button @click="loadOne" :disabled="loading">换一个</el-button>
|
||
</div>
|
||
|
||
<el-result v-if="result" :icon="result.correct ? 'success' : 'error'" :title="result.correct ? '正确' : '不对'" style="margin-top:16px">
|
||
<template #sub-title>
|
||
<div>单词:{{ result.word.word }} / 释义:{{ result.word.definition }}</div>
|
||
<div v-if="!result.correct">你的答案:{{ result.answer }};正确:{{ result.correct_ans }}</div>
|
||
</template>
|
||
</el-result>
|
||
</div>
|
||
</el-card>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { computed, ref } from 'vue'
|
||
import { audioUrl, getReviewWords, submitReview } from '../services/api'
|
||
|
||
import type { MemoryRecord, ReviewMode, ReviewResult } from '../services/api'
|
||
|
||
const mode = ref<ReviewMode>('spelling')
|
||
const record = ref<MemoryRecord | null>(null) // MemoryRecord (含 word)
|
||
const answer = ref('')
|
||
const loading = ref(false)
|
||
const result = ref<ReviewResult | null>(null)
|
||
|
||
const modeHint = computed(() => {
|
||
if (mode.value === 'spelling') return '听读音,拼写单词'
|
||
if (mode.value === 'en2cn') return '看到英文,写中文意思(允许包含匹配)'
|
||
return '看到中文意思,写英文单词'
|
||
})
|
||
|
||
async function loadOne() {
|
||
result.value = null
|
||
answer.value = ''
|
||
const res = await getReviewWords({ mode: mode.value, limit: 1 })
|
||
const arr = (res as any).data ?? (res as any)
|
||
record.value = Array.isArray(arr) && arr.length ? (arr[0] as MemoryRecord) : null
|
||
}
|
||
|
||
function play() {
|
||
if (!record.value?.word?.word) return
|
||
const a = new Audio(audioUrl(record.value.word.word, 'uk'))
|
||
a.play()
|
||
}
|
||
|
||
async function submit() {
|
||
if (!record.value) return
|
||
if (!answer.value.trim()) return
|
||
loading.value = true
|
||
try {
|
||
const res = await submitReview({ recordId: record.value.id, answer: answer.value, mode: mode.value })
|
||
result.value = (res as any).data ?? (res as any)
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
loadOne().catch(console.error)
|
||
</script>
|
||
|
||
<style scoped>
|
||
.wrap{padding:24px;}
|
||
.h{display:flex; align-items:center; justify-content:space-between; gap:12px;}
|
||
.title{font-size:22px; font-weight:700;}
|
||
.q{font-size:24px; font-weight:700;}
|
||
</style>
|