68c5efe573
Includes per-word training stats and curves, quiz session auto-save, remember-login, paginated word list with floating page arrows, and Obsidian-style relationship graph baseline. Co-authored-by: Cursor <cursoragent@cursor.com>
137 lines
2.7 KiB
Vue
137 lines
2.7 KiB
Vue
<script setup lang="ts">
|
||
import { ref, watch } from 'vue'
|
||
import type { QuizQuestion } from '../api/request'
|
||
|
||
const props = defineProps<{
|
||
question: QuizQuestion
|
||
index: number
|
||
total: number
|
||
showResult?: boolean
|
||
isCorrect?: boolean
|
||
submittedAnswer?: string
|
||
}>()
|
||
|
||
const emit = defineEmits<{
|
||
submit: [answer: string]
|
||
}>()
|
||
|
||
const input = ref('')
|
||
|
||
watch(
|
||
() => props.index,
|
||
() => {
|
||
input.value = ''
|
||
}
|
||
)
|
||
|
||
function onSubmit() {
|
||
const answer = input.value.trim()
|
||
if (!answer || props.showResult) return
|
||
emit('submit', answer)
|
||
}
|
||
|
||
defineExpose({
|
||
getDraft: () => input.value.trim(),
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<div class="card quiz-card">
|
||
<div class="quiz-progress">{{ index + 1 }} / {{ total }}</div>
|
||
<div class="quiz-type">根据中文与读音拼写英文</div>
|
||
<div class="quiz-prompt">{{ question.prompt }}</div>
|
||
<div v-if="question.phonetic" class="phonetic">{{ question.phonetic }}</div>
|
||
<div v-else class="phonetic muted">暂无音标</div>
|
||
<input
|
||
v-model="input"
|
||
class="spell-input"
|
||
type="text"
|
||
placeholder="输入英文单词"
|
||
autocomplete="off"
|
||
autocapitalize="off"
|
||
spellcheck="false"
|
||
:disabled="showResult"
|
||
@keydown.enter="onSubmit"
|
||
/>
|
||
<button
|
||
v-if="!showResult"
|
||
class="btn btn-primary submit-btn"
|
||
:disabled="!input.trim()"
|
||
@click="onSubmit"
|
||
>
|
||
提交
|
||
</button>
|
||
<div v-if="showResult" class="result" :class="isCorrect ? 'ok' : 'fail'">
|
||
{{ isCorrect ? '拼写正确 ✅' : '拼写错误 ❌' }}
|
||
<template v-if="!isCorrect">
|
||
— 你的答案:{{ submittedAnswer }} · 正确答案:{{ question.correct_answer }}
|
||
</template>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.quiz-progress {
|
||
font-size: 13px;
|
||
color: var(--muted);
|
||
margin-bottom: 8px;
|
||
}
|
||
.quiz-type {
|
||
font-size: 12px;
|
||
color: var(--primary);
|
||
margin-bottom: 8px;
|
||
}
|
||
.quiz-prompt {
|
||
font-size: 28px;
|
||
font-weight: 700;
|
||
text-align: center;
|
||
margin: 20px 0 8px;
|
||
}
|
||
.phonetic {
|
||
text-align: center;
|
||
font-size: 18px;
|
||
color: var(--primary);
|
||
margin-bottom: 20px;
|
||
}
|
||
.phonetic.muted {
|
||
color: var(--muted);
|
||
font-size: 14px;
|
||
}
|
||
.spell-input {
|
||
width: 100%;
|
||
padding: 14px 16px;
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
font-size: 18px;
|
||
text-align: center;
|
||
box-sizing: border-box;
|
||
}
|
||
.spell-input:focus {
|
||
outline: none;
|
||
border-color: var(--primary);
|
||
}
|
||
.spell-input:disabled {
|
||
background: #f3f4f6;
|
||
}
|
||
.submit-btn {
|
||
width: 100%;
|
||
margin-top: 12px;
|
||
}
|
||
.result {
|
||
margin-top: 16px;
|
||
padding: 12px;
|
||
border-radius: var(--radius);
|
||
font-size: 14px;
|
||
text-align: center;
|
||
line-height: 1.5;
|
||
}
|
||
.result.ok {
|
||
background: #d1fae5;
|
||
color: #047857;
|
||
}
|
||
.result.fail {
|
||
background: #fee2e2;
|
||
color: #b91c1c;
|
||
}
|
||
</style>
|