change to vite and enabled typescript
This commit is contained in:
@@ -0,0 +1,440 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-page-header style="margin-top:20px;margin-left:20px" @back="$router.push('/')">
|
||||
<template #content>
|
||||
<span class="text-large font-600 mr-3"> 背诵 </span>
|
||||
</template>
|
||||
</el-page-header>
|
||||
<div id="test" class="colbox">
|
||||
<div style="flex-grow: 1;" class="card">
|
||||
<div id="status">背诵进度: {{ current + 1 }}/{{ total }}</div>
|
||||
<div>
|
||||
<textarea autofocus id="input" ref="inputAreaRef" v-if="current === answered" @input="change"
|
||||
class="answer" spellcheck="false">
|
||||
</textarea>
|
||||
<div v-if="current < answered" class="answer">{{ word.word }}</div>
|
||||
</div>
|
||||
<div id="explain">
|
||||
<el-button v-if="current > 0" @click="prev">上一个</el-button>
|
||||
<el-button v-if="current < answered" @click="next">下一个</el-button>
|
||||
<el-button v-if="current === answered" @click="showAnswer">显示答案</el-button>
|
||||
<el-button v-if="current === answered" type="warning" @click="skip">跳过</el-button>
|
||||
<el-button @click="terminate" type="danger">停止背诵</el-button>
|
||||
<box-icon color="var(--text-color)" class="btn" style="margin-left: 10px;translate: 0 4px;"
|
||||
@click="audio_play" name='volume-full'></box-icon>
|
||||
</div>
|
||||
<div id="trans">{{ word.type }} {{ word.trans }}</div>
|
||||
</div>
|
||||
<div id="add-to-box" class="card">
|
||||
<el-text class="mx-1 title">加入至</el-text>
|
||||
<div class="colbox para">
|
||||
<div class="mid-text">分组:</div>
|
||||
<el-select v-model="set_class" class="m-2" placeholder="Select">
|
||||
<el-option v-for="item in wordsets._allclass" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="colbox para">
|
||||
<div class="mid-text">单词本:</div>
|
||||
<el-select v-model="set_id" class="m-2" placeholder="Select">
|
||||
<el-option v-for="item in wordsets.getClass(set_class)" :key="item.id" :label="item.name"
|
||||
:value="item.id" />
|
||||
</el-select>
|
||||
</div>
|
||||
<el-button @click="add_to" type="primary">添加</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { ElMessage, ElNotification, ElMessageBox } from 'element-plus';
|
||||
import { useMainStore } from '@/store';
|
||||
import { WordItem } from '@/types';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const store = useMainStore();
|
||||
|
||||
interface Settings {
|
||||
direct_answer: boolean;
|
||||
}
|
||||
|
||||
const wordsets = ref(store.wordsets)
|
||||
const testWords = ref<WordItem[]>([]);
|
||||
const seq = ref<number[]>([]);
|
||||
const total = ref(0);
|
||||
const current = ref(0);
|
||||
const answered = ref(0);
|
||||
const word = ref<WordItem>({} as WordItem);
|
||||
const set_class = ref("");
|
||||
const set_id = ref("");
|
||||
const settings = ref<Settings>({
|
||||
direct_answer: false,
|
||||
});
|
||||
const inputAreaRef = ref<HTMLTextAreaElement | null>(null)
|
||||
|
||||
const key_listener = (event: KeyboardEvent) => {
|
||||
let ctrlKey = event.ctrlKey || event.metaKey;
|
||||
if (ctrlKey) {
|
||||
switch (event.key) {
|
||||
case 'b':
|
||||
showAnswer();
|
||||
break;
|
||||
case 'm':
|
||||
skip();
|
||||
break;
|
||||
case 'i':
|
||||
add_to();
|
||||
break;
|
||||
case 'ArrowLeft':
|
||||
prev();
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
next();
|
||||
break;
|
||||
case 'y':
|
||||
audio_play();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
const next = () => {
|
||||
if (current.value < answered.value) {
|
||||
current.value++;
|
||||
if (current.value === total.value) {
|
||||
ElNotification({
|
||||
message: "您已完成所有单词的背诵",
|
||||
title: "Congratulations!",
|
||||
type: "success"
|
||||
});
|
||||
router.push('/');
|
||||
return;
|
||||
}
|
||||
nextTick(() => {
|
||||
show();
|
||||
});
|
||||
} else {
|
||||
ElMessage({
|
||||
type: "error",
|
||||
message: "您还未答过该词,跳过请使用ctrl+M",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const skip = () => {
|
||||
ElMessage({
|
||||
message: "已经跳过该词",
|
||||
type: "info"
|
||||
});
|
||||
answered.value++;
|
||||
store.history.count(answered.value);
|
||||
next();
|
||||
};
|
||||
|
||||
const prev = () => {
|
||||
if (current.value > 0) {
|
||||
current.value--;
|
||||
show();
|
||||
} else {
|
||||
ElMessage({
|
||||
type: 'error',
|
||||
message: "已经是第一个单词"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const showAnswer = () => {
|
||||
if (!settings.value.direct_answer) {
|
||||
if (inputAreaRef.value) {
|
||||
const inputArea = inputAreaRef.value;
|
||||
if (inputArea.value === "_".repeat(word.value.word.length)) {
|
||||
inputArea.value = word.value.word[0] + "_".repeat(word.value.word.length - 1);
|
||||
inputArea.setSelectionRange(1, 1);
|
||||
ElMessage(`首字母为:${word.value.word[0]}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
ElMessage(`答案:${word.value.word}`);
|
||||
};
|
||||
|
||||
const show = () => {
|
||||
word.value = testWords.value[seq.value[current.value]];
|
||||
if (current.value === answered.value) {
|
||||
if (inputAreaRef.value) {
|
||||
const inputArea = inputAreaRef.value;
|
||||
inputArea.value = "_".repeat(word.value.word.length);
|
||||
inputArea.setSelectionRange(0, 0);
|
||||
inputArea.style.height = "0";
|
||||
setTimeout(() => {
|
||||
inputArea.style.height = `${inputArea.scrollHeight}px`;
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const change = () => {
|
||||
if (inputAreaRef.value) {
|
||||
const inputArea = inputAreaRef.value;
|
||||
const cur = inputArea.selectionStart;
|
||||
const value = inputArea.value;
|
||||
const n = value.indexOf("_");
|
||||
let content: string;
|
||||
|
||||
if (n == word.value.word.length) {
|
||||
if (value.substring(0, value.length - 1).toLowerCase() == word.value.word.toLowerCase()) {
|
||||
ElMessage.success("正确");
|
||||
answered.value++;
|
||||
store.history.count(answered.value);
|
||||
next();
|
||||
return;
|
||||
}
|
||||
ElMessage.error("错误");
|
||||
content = "_".repeat(word.value.word.length);
|
||||
inputArea.value = content;
|
||||
inputArea.setSelectionRange(0, 0);
|
||||
inputArea.style.height = "0";
|
||||
setTimeout(() => {
|
||||
inputArea.style.height = `${inputArea.scrollHeight}px`;
|
||||
}, 200);
|
||||
return;
|
||||
} else {
|
||||
n == -1 ? content = "_".repeat(word.value.word.length) : (content = value.substring(0, n),
|
||||
content += "_".repeat(word.value.word.length - n));
|
||||
inputArea.value = content;
|
||||
if (cur && cur > n) {
|
||||
inputArea.setSelectionRange(n, n);
|
||||
} else if (cur !== null) {
|
||||
inputArea.setSelectionRange(cur, cur);
|
||||
}
|
||||
}
|
||||
setTimeout(() => {
|
||||
const height = parseInt(inputArea.style.height || '0');
|
||||
if (height < inputArea.scrollHeight) {
|
||||
inputArea.style.height = `${inputArea.scrollHeight}px`;
|
||||
}
|
||||
}, 0);
|
||||
inputArea.focus();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const audio_play = () => {
|
||||
const t = new Audio("https://dict.youdao.com/dictvoice?audio=" + word.value.word);
|
||||
t.play();
|
||||
};
|
||||
|
||||
const terminate = () => {
|
||||
ElMessageBox.confirm("确定要终止吗?")
|
||||
.then(() => {
|
||||
router.push('/');
|
||||
ElNotification({
|
||||
message: "背诵已终止",
|
||||
type: "info",
|
||||
title: "Terminate"
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const add_to = () => {
|
||||
if (set_id.value) {
|
||||
const data = JSON.parse(localStorage.getItem(set_id.value) || '[]');
|
||||
for (let i of data) {
|
||||
if (i.word === word.value.word) {
|
||||
ElMessage({
|
||||
message: '已经添加过该词',
|
||||
type: 'error',
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
data.push(word.value);
|
||||
localStorage.setItem(set_id.value, JSON.stringify(data));
|
||||
ElMessage({
|
||||
message: `已添加 ${word.value.word} (${word.value.type})`,
|
||||
type: 'success',
|
||||
});
|
||||
} else {
|
||||
ElMessage({
|
||||
message: '请先选择单词本',
|
||||
type: 'error',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('keyup', key_listener);
|
||||
const index = route.query.index;
|
||||
if (index) {
|
||||
store.history.use(Number(index));
|
||||
}
|
||||
|
||||
store.history.init_recite((words: WordItem[], currentVal: number, seqVal: number[], settingsVal: Settings) => {
|
||||
testWords.value = words;
|
||||
current.value = currentVal;
|
||||
total.value = words.length;
|
||||
answered.value = currentVal;
|
||||
settings.value = settingsVal;
|
||||
seq.value = seqVal;
|
||||
|
||||
if (answered.value >= total.value) {
|
||||
answered.value = 0;
|
||||
current.value = 0;
|
||||
ElMessage({
|
||||
type: 'warning',
|
||||
message: "进度已经重置"
|
||||
});
|
||||
store.history.count(answered.value);
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
show();
|
||||
});
|
||||
}, (msg: string) => {
|
||||
ElMessage({
|
||||
type: 'error',
|
||||
message: msg
|
||||
});
|
||||
router.push('/select');
|
||||
});
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener("keyup", key_listener);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@media screen and (max-width: 500px) {
|
||||
|
||||
.title {
|
||||
font-size: 30px;
|
||||
font-weight: 800;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
#test {
|
||||
flex-direction: column;
|
||||
animation: enter .5s ease-out;
|
||||
}
|
||||
|
||||
#trans {
|
||||
font-size: 25px;
|
||||
transition: .5s;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
#explain {
|
||||
font-size: 18px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
width: 55px;
|
||||
height: 28px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.tbtn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.answer {
|
||||
font-size: 55px;
|
||||
letter-spacing: 15px;
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
.card {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
font-size: 30px;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 500px) {
|
||||
.item {
|
||||
margin-bottom: 20px;
|
||||
/* background-color: var(--bg-color); */
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.tbtn {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 35px;
|
||||
font-weight: 800;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
#test {
|
||||
padding: 30px;
|
||||
animation: enter .5s ease-out;
|
||||
}
|
||||
|
||||
#trans {
|
||||
font-size: 43px;
|
||||
transition: .5s;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#add-to-box {
|
||||
width: 30%;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
#explain {
|
||||
font-size: 25px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.answer {
|
||||
font-size: 70px;
|
||||
letter-spacing: 25px;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
font-size: 30px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
height: calc(100% - 10px);
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 10px;
|
||||
height: calc(100% - 50px);
|
||||
}
|
||||
|
||||
#status {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.answer {
|
||||
margin-top: 10px;
|
||||
border-radius: 8px;
|
||||
background-color: var(--bg-color);
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
border: none;
|
||||
outline-style: none;
|
||||
padding: 0;
|
||||
transition: .5s;
|
||||
resize: vertical;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user