wordIn/src/views/recite/SelectView.vue

346 lines
11 KiB
Vue

<template>
<div class="container" id="page">
<el-page-header @back="router.push('/');"
style="width: calc(100% - 30px);margin-left: 30px;margin-top: 5px;">
<template #content>
<span class="text-large font-600 mr-3">开始新背诵</span>
</template>
</el-page-header>
<el-steps style="width: 100%;" align-center :active="step">
<el-step title="选择单词本" description="选择在线或本地单词本以开始背诵"></el-step>
<el-step title="自定义背诵" description="您可以在此处更改背诵设置"></el-step>
</el-steps>
<div id="main" class="card" style="overflow: hidden;">
<div class="item" id="select-area" v-show="step === 1">
<el-tabs style="height: calc(100% - 40px);position: relative;overflow: hidden;">
<el-tab-pane label="本地">
<el-checkbox v-model="local.checkAll" :indeterminate="local.isIndeterminate"
@change="(res: boolean) => { handleCheckAllChange(local, res) }" size="large">全选</el-checkbox>
<el-checkbox-group v-model="local.checkedSets" @change="(res: string[]) => { handleChange(local, res) }">
<div class="set_radios" v-for="(set_class, set_class_name) in store.wordsets._inner"
:key="set_class_name">
<p class="mb-4 mt-2">{{ set_class_name }}</p>
<el-checkbox class="checkbox" v-for="set in set_class" :key="set.id" :label="set.id"
size="large" border>
<div style="font-size: 18px;font-weight: 500;">
{{ set.name }}
</div>
</el-checkbox>
</div>
</el-checkbox-group>
</el-tab-pane>
<el-tab-pane label="在线">
<el-checkbox v-model="online.checkAll" :indeterminate="online.isIndeterminate"
@change="(res: boolean) => { handleCheckAllChange(online, res) }" size="large">全选</el-checkbox>
<el-checkbox-group v-model="online.checkedSets"
@change="(res: string[]) => { handleChange(online, res) }">
<div class="set_radios" v-for="(set, set_name) in online_sets" :key="set_name">
<div class="subtitle">{{ set_name }}</div>
<div v-for="(book, book_name) in set" :key="book_name">
<p class="mb-4 mt-2">{{ book_name }}</p>
<el-checkbox class="checkbox" v-for="(config, id) in book" :key="id" :label="id"
size="large" border>
<div style="font-size: 18px;font-weight: 500;">
{{ config.name }}
</div>
</el-checkbox>
</div>
</div>
</el-checkbox-group>
</el-tab-pane>
</el-tabs>
<el-button style="position: absolute;margin-top: 10px;right: 30px;" type="primary"
@click="completeSelect">下一步</el-button>
</div>
<div class="item" id="setting-area" v-show="step === 2">
<div style="margin: 20px;">
<div class="setting-item">
<div class="setting-header">
<div style="font-size: 20px;">随机顺序</div>
<div style="font-size: 14px;">开启后单词顺序将打乱</div>
</div>
<el-switch @change="update" v-model="settings.shuffle" active-color="#13ce66"></el-switch>
</div>
<div class="setting-item">
<div class="setting-header">
<div style="font-size: 20px;">直接显示答案</div>
<div style="font-size: 14px;">开启后答案提示不会先提示首字母</div>
</div>
<el-switch @change="update" v-model="settings.direct_answer" active-color="#13ce66"></el-switch>
</div>
<div class="setting-item">
<div class="setting-header">
<div style="font-size: 20px;">忽略词组</div>
<div style="font-size: 14px;">开启后不背诵词组</div>
</div>
<el-switch @change="update" v-model="settings.ignore_phrases"
active-color="#13ce66"></el-switch>
</div>
<el-button style="position: absolute;left: 30px;bottom: 30px;" @click="backSelect">上一步</el-button>
<el-button style="position: absolute;right: 30px;bottom: 30px;" type="primary"
@click="startRecite">下一步</el-button>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import { useRouter } from 'vue-router';
import { useMainStore } from '@/store';
import axios from '@/scripts/request';
const router = useRouter();
const store = useMainStore();
interface WordSetState {
allsets: string[];
checkedSets: string[];
isIndeterminate: boolean;
checkAll: boolean;
}
interface ReciteSettings {
shuffle: boolean;
direct_answer: boolean;
ignore_phrases: boolean;
}
interface OnlineIdInfo {
set: string;
book: string;
}
const step = ref(1);
const local = reactive<WordSetState>({
allsets: [],
checkedSets: [],
isIndeterminate: false,
checkAll: false,
});
const online = reactive<WordSetState>({
allsets: [],
checkedSets: [],
isIndeterminate: false,
checkAll: false,
});
const online_sets = ref<Record<string, any>>({});
const online_ids = ref<Record<string, OnlineIdInfo>>({});
const settings = reactive<ReciteSettings>({
shuffle: true,
direct_answer: false,
ignore_phrases: true,
});
const handleCheckAllChange = (range: WordSetState, val: boolean) => {
range.checkedSets = val ? range.allsets : [];
range.isIndeterminate = false;
};
const handleChange = (range: WordSetState, value: string[]) => {
range.checkAll = value.length === range.allsets.length;
range.isIndeterminate = value.length > 0 && value.length < range.allsets.length;
};
const completeSelect = () => {
if (online.checkedSets.length + local.checkedSets.length > 0) {
const selectArea = document.getElementById("select-area");
if (selectArea) selectArea.style.animation = "exitLeft .25s ease-in forwards";
setTimeout(() => {
const settingArea = document.getElementById("setting-area");
if (settingArea) settingArea.style.animation = "enterRight .25s ease-out forwards";
step.value++;
}, 250);
return;
}
ElMessage({
type: 'error',
message: "请选择单词本",
});
};
const backSelect = () => {
const settingArea = document.getElementById("setting-area");
if (settingArea) settingArea.style.animation = "exitRight .25s ease-in forwards";
setTimeout(() => {
step.value--;
setTimeout(() => {
const selectArea = document.getElementById("select-area");
if (selectArea) selectArea.style.animation = "enterLeft .25s ease-out forwards";
}, 0);
}, 250);
};
const startRecite = () => {
const onlinesets = [];
for (let i of online.checkedSets) {
onlinesets.push(Object.assign({ id: i }, online_ids.value[i]));
}
store.history.add(local.checkedSets, onlinesets, settings, () => {
router.push('/recite');
});
};
const update = () => {
// Method to handle switch changes if needed
};
onMounted(() => {
for (let i of store.wordsets._allsets) {
for (let j of i) {
local.allsets.push(j.id);
}
}
axios.get("wordset/list").then((res: any) => {
online_sets.value = res.data;
for (let i in online_sets.value) {
for (let j in online_sets.value[i]) {
for (let k in online_sets.value[i][j]) {
online.allsets.push(k);
online_ids.value[k] = {
set: i,
book: j
};
}
}
}
}).catch(()=> {
ElMessage({
message: "在线词库加载失败",
type: "error"
});
});
});
</script>
<style scoped>
@media screen and (max-width: 500px) {
.checkbox {
font-size: 30px;
margin-bottom: 10px;
margin-right: 15px;
}
}
@media screen and (min-width: 500px) {
.checkbox {
font-size: 30px;
margin-bottom: 10px;
}
}
#page {
width: 100%;
/* margin: 20px; */
align-items: center;
display: flex;
flex-direction: column;
margin-top: 10px;
}
.subtitle {
font-size: 23px;
line-height: 35px;
margin-bottom: 15px;
font-weight: 800;
}
.set_radios {
margin: 10px;
}
.set_radios p {
font-size: 18px;
font-weight: 700;
color: var(--text-color);
}
#main {
margin-top: 10px;
height: calc(100% - 250px);
width: 90%;
}
.item {
height: 100%;
position: relative;
}
.el-tab-pane {
height: 100%;
overflow: auto;
}
.setting-header {
min-width: 25%;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: self-start;
}
.setting-item {
margin-bottom: 30px;
display: flex;
flex-direction: row;
justify-content: space-between;
height: 40px;
align-items: center;
}
</style>
<style>
.el-tabs__content {
height: calc(100% - 50px);
}
@keyframes exitLeft {
0% {
opacity: 1;
transform: translateX(0);
}
100% {
opacity: 0;
transform: translateX(-50px);
}
}
@keyframes exitRight {
0% {
opacity: 1;
transform: translateX(0);
}
100% {
opacity: 0;
transform: translateX(50px);
}
}
@keyframes enterLeft {
0% {
opacity: 0;
transform: translateX(-50px);
}
100% {
opacity: 1;
}
}
@keyframes enterRight {
0% {
opacity: 0;
transform: translateX(50px);
}
100% {
opacity: 1;
}
}
</style>