refactor(web): restructure Vue3 app layout
This commit is contained in:
99
memora-web/src/views/Review.vue
Normal file
99
memora-web/src/views/Review.vue
Normal file
@@ -0,0 +1,99 @@
|
||||
<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>
|
||||
import { computed, ref } from 'vue'
|
||||
import { audioUrl, getReviewWords, submitReview } from '../services/api'
|
||||
|
||||
const mode = ref('spelling')
|
||||
const record = ref(null) // MemoryRecord (含 word)
|
||||
const answer = ref('')
|
||||
const loading = ref(false)
|
||||
const result = ref(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.data ?? res
|
||||
record.value = Array.isArray(arr) && arr.length ? arr[0] : null
|
||||
}
|
||||
|
||||
function play() {
|
||||
if (!record.value?.word?.word) return
|
||||
const a = new Audio(audioUrl({ word: record.value.word.word, type: '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.data ?? res
|
||||
} 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>
|
||||
Reference in New Issue
Block a user