rebuild
parent
36891a901a
commit
eb4010bef0
|
|
@ -12,6 +12,7 @@
|
||||||
"boxicons": "^2.1.4",
|
"boxicons": "^2.1.4",
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
"crypto-js": "^4.1.1",
|
"crypto-js": "^4.1.1",
|
||||||
|
"marked": "^11.1.1",
|
||||||
"node-uuid": "^1.4.8",
|
"node-uuid": "^1.4.8",
|
||||||
"vue": "^3.2.13",
|
"vue": "^3.2.13",
|
||||||
"vue-router": "^4.2.5",
|
"vue-router": "^4.2.5",
|
||||||
|
|
@ -7695,6 +7696,17 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/marked": {
|
||||||
|
"version": "11.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/marked/-/marked-11.1.1.tgz",
|
||||||
|
"integrity": "sha512-EgxRjgK9axsQuUa/oKMx5DEY8oXpKJfk61rT5iY3aRlgU6QJtUcxU5OAymdhCvWvhYcd9FKmO5eQoX8m9VGJXg==",
|
||||||
|
"bin": {
|
||||||
|
"marked": "bin/marked.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mdn-data": {
|
"node_modules/mdn-data": {
|
||||||
"version": "2.0.14",
|
"version": "2.0.14",
|
||||||
"resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.14.tgz",
|
"resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.14.tgz",
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
"boxicons": "^2.1.4",
|
"boxicons": "^2.1.4",
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
"crypto-js": "^4.1.1",
|
"crypto-js": "^4.1.1",
|
||||||
|
"marked": "^11.1.1",
|
||||||
"node-uuid": "^1.4.8",
|
"node-uuid": "^1.4.8",
|
||||||
"vue": "^3.2.13",
|
"vue": "^3.2.13",
|
||||||
"vue-router": "^4.2.5",
|
"vue-router": "^4.2.5",
|
||||||
|
|
|
||||||
62
src/App.vue
62
src/App.vue
|
|
@ -1,8 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
|
<div id="navibar" class="pconly" >
|
||||||
|
<div class="navi-item"><el-link @click="go('/')" id="logo">wordIn</el-link></div>
|
||||||
|
<div class="navi-item"><el-link @click="go('/recite')" class="link">背诵</el-link></div>
|
||||||
|
<div class="navi-item"><el-link @click="go('/manage')" class="link">编辑单词本</el-link></div>
|
||||||
|
</div>
|
||||||
<router-view style="margin-top: 10px;"></router-view>
|
<router-view style="margin-top: 10px;"></router-view>
|
||||||
|
<!-- <div id="navibar" class="mbonly"></div> -->
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import _wordsets from './js/wordsets'
|
||||||
|
|
||||||
window.htmlClasses = [];
|
window.htmlClasses = [];
|
||||||
window.addHtmlclasses = (classname) => {
|
window.addHtmlclasses = (classname) => {
|
||||||
|
|
@ -30,13 +37,13 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
change(index) {
|
change(index) {
|
||||||
this.index = index;
|
this.index = index;
|
||||||
|
},
|
||||||
|
go(path) {
|
||||||
|
this.$router.push(path);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
let wordsets = localStorage.getItem("wordsets");
|
this.$store.state.wordsets = new _wordsets();
|
||||||
if (wordsets) {
|
|
||||||
window.wordsets = JSON.parse(wordsets);
|
|
||||||
} else window.wordsets = {};
|
|
||||||
let res = localStorage.getItem("bgimg");
|
let res = localStorage.getItem("bgimg");
|
||||||
if (res) {
|
if (res) {
|
||||||
document.body.style.backgroundImage = `url("${res}")`;
|
document.body.style.backgroundImage = `url("${res}")`;
|
||||||
|
|
@ -84,13 +91,13 @@ export default {
|
||||||
0% {
|
0% {
|
||||||
translate: 100px 0;
|
translate: 100px 0;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
filter: blur(20px);
|
/* filter: blur(20px); */
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
translate: 0 0;
|
translate: 0 0;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
filter: blur(0px);
|
/* filter: blur(0px); */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -98,15 +105,16 @@ export default {
|
||||||
html {
|
html {
|
||||||
--bg-color: #ffffffae;
|
--bg-color: #ffffffae;
|
||||||
--text-color: #464646;
|
--text-color: #464646;
|
||||||
|
--bd-color: #737373;
|
||||||
}
|
}
|
||||||
|
|
||||||
html.dark {
|
html.dark {
|
||||||
--bg-color: #2a2a2aae;
|
--bg-color: #2a2a2a88;
|
||||||
--text-color: #c0c0c0;
|
--text-color: #c0c0c0;
|
||||||
|
--bd-color: #7f7f7f7c;
|
||||||
|
--navi-bg-color: #131313e2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
height: calc(100% - 20px);
|
height: calc(100% - 20px);
|
||||||
width: calc(100% - 20px);
|
width: calc(100% - 20px);
|
||||||
|
|
@ -126,10 +134,14 @@ html.dark {
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: var(--el-box-shadow);
|
border: solid 1px var(--bd-color);
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
|
transition: .5s;
|
||||||
|
}
|
||||||
|
.card:hover{
|
||||||
|
box-shadow: var(--el-box-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
html.bgimged .card {
|
html.bgimged .card {
|
||||||
|
|
@ -153,3 +165,33 @@ html.bgimged .card {
|
||||||
margin: 15px;
|
margin: 15px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
#navibar {
|
||||||
|
height: 50px;
|
||||||
|
border-bottom: solid 1px var(--bd-color);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
background-color: var(--navi-bg-color);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navi-item {
|
||||||
|
height: 100%;
|
||||||
|
font-size: 22px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: baseline;
|
||||||
|
margin-left: 20px;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
#logo {
|
||||||
|
font-size: 28px;
|
||||||
|
margin-right: 20px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<div id="main">
|
<div id="main">
|
||||||
<div id="title"> WordIn</div>
|
<div id="title"> WordIn</div>
|
||||||
<div class="colbox">
|
<div class="colbox">
|
||||||
<router-link to="/recite" class="button">
|
<router-link to="/select" class="button">
|
||||||
背诵
|
背诵
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link to="/manage" class="button">
|
<router-link to="/manage" class="button">
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="flex-grow: 1;" class="card">
|
<div style="flex-grow: 1;" class="card">
|
||||||
<el-table :data="table" style="max-height: 550px;overflow: auto;border-radius: 10px;">
|
<el-table :data="table" style="height: calc(100% - 10px);overflow: auto;border-radius: 10px;">
|
||||||
<el-table-column type="index" />
|
<el-table-column type="index" />
|
||||||
<el-table-column prop="word" label="单词" />
|
<el-table-column prop="word" label="单词" />
|
||||||
<el-table-column prop="type" label="词性" />
|
<el-table-column prop="type" label="词性" />
|
||||||
|
|
@ -75,7 +75,6 @@ export default {
|
||||||
name: "NoteEditor",
|
name: "NoteEditor",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
wordsets: window.wordsets,
|
|
||||||
new_word: {
|
new_word: {
|
||||||
word: "",
|
word: "",
|
||||||
trans: "",
|
trans: "",
|
||||||
|
|
@ -91,6 +90,8 @@ export default {
|
||||||
table: [],
|
table: [],
|
||||||
word_editing: false,
|
word_editing: false,
|
||||||
new_name: "",
|
new_name: "",
|
||||||
|
name:"",
|
||||||
|
id:""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -112,7 +113,7 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.table.push(Object.assign({}, this.new_word));
|
this.table.push(Object.assign({}, this.new_word));
|
||||||
localStorage.setItem(this.editing.id, JSON.stringify(this.table));
|
this.$store.state.wordsets.saveSet(this.id,this.table);
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: `已添加 ${this.new_word.word} (${this.new_word.type})`,
|
message: `已添加 ${this.new_word.word} (${this.new_word.type})`,
|
||||||
type: 'success',
|
type: 'success',
|
||||||
|
|
@ -142,7 +143,7 @@ export default {
|
||||||
type: this.editing_word.type,
|
type: this.editing_word.type,
|
||||||
trans: this.editing_word.trans,
|
trans: this.editing_word.trans,
|
||||||
}
|
}
|
||||||
localStorage.setItem(this.editing.id, JSON.stringify(this.table));
|
this.$store.state.wordsets.saveSet(this.id,this.table);
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: `已保存更改`,
|
message: `已保存更改`,
|
||||||
type: 'success',
|
type: 'success',
|
||||||
|
|
@ -150,11 +151,11 @@ export default {
|
||||||
this.word_editing = false;
|
this.word_editing = false;
|
||||||
},
|
},
|
||||||
change_name() {
|
change_name() {
|
||||||
let old_name = this.editing.name;
|
let old_name = this.name;
|
||||||
this.editing.name = this.new_name;
|
this.name = this.new_name;
|
||||||
localStorage.setItem("wordsets", JSON.stringify(this.wordsets));
|
this.$store.state.wordsets.renameSet(this.class_name,this.id,this.new_name);
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: `已更改 ${old_name} 为 ${this.new_name}`,
|
message: `已更改 ${old_name} 为 ${this.name}`,
|
||||||
type: 'success',
|
type: 'success',
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
|
@ -162,7 +163,7 @@ export default {
|
||||||
del_word(index) {
|
del_word(index) {
|
||||||
let word = this.table[index].word.concat();
|
let word = this.table[index].word.concat();
|
||||||
this.table.splice(index, 1);
|
this.table.splice(index, 1);
|
||||||
localStorage.setItem(this.editing.id, JSON.stringify(this.table));
|
this.$store.state.wordsets.saveSet(this.id,this.table);
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: `已删除 ${word}`,
|
message: `已删除 ${word}`,
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
|
|
@ -171,10 +172,14 @@ export default {
|
||||||
|
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.name = this.$route.query.name;
|
this.class_name = this.$route.query.classname;
|
||||||
this.id = this.$route.query.id;
|
this.id = this.$route.query.id;
|
||||||
if(this.name && this.id){
|
if(this.id){
|
||||||
this.table = JSON.parse(localStorage.getItem(this.id));
|
let status = this.$store.state.wordsets.getSetStatus(this.class_name,this.id);
|
||||||
|
if(status){
|
||||||
|
this.name = status.name;
|
||||||
|
}
|
||||||
|
this.table = this.$store.state.wordsets.getSet(this.id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@
|
||||||
<div class="mid-text">名称:</div>
|
<div class="mid-text">名称:</div>
|
||||||
<el-input v-model="set_name"></el-input>
|
<el-input v-model="set_name"></el-input>
|
||||||
<div class="mid-text">分组:</div>
|
<div class="mid-text">分组:</div>
|
||||||
<el-select allow-create filterable v-model="new_set_class" class="m-2" placeholder="Select">
|
<el-select allow-create filterable default-first-option v-model="new_set_class" class="m-2" placeholder="输入新单词本类后后请按回车">
|
||||||
<el-option v-for="item in Object.keys(wordsets)" :key="item" :label="item" :value="item" />
|
<el-option v-for="item in $store.state.wordsets._allclass" :key="item" :label="item" :value="item" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
<el-button style="width: 50%;margin-top: 20px;" type="primary" @click="new_wordset()">创建</el-button>
|
<el-button style="width: 50%;margin-top: 20px;" type="primary" @click="new_wordset()">创建</el-button>
|
||||||
|
|
@ -20,14 +20,12 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import uuid from 'node-uuid';
|
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "NewSet",
|
name: "NewSet",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
wordsets: window.wordsets,
|
|
||||||
set_name: "",
|
set_name: "",
|
||||||
new_set_class: "",
|
new_set_class: "",
|
||||||
}
|
}
|
||||||
|
|
@ -41,17 +39,7 @@ export default {
|
||||||
})
|
})
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!this.wordsets[this.new_set_class]) {
|
this.$store.state.wordsets.addSet(this.new_set_class,this.set_name);
|
||||||
this.wordsets[this.new_set_class] = [];
|
|
||||||
}
|
|
||||||
let id = uuid.v1();
|
|
||||||
this.wordsets[this.new_set_class].push({
|
|
||||||
name: this.set_name,
|
|
||||||
created: (new Date()).getTime(),
|
|
||||||
id: id
|
|
||||||
});
|
|
||||||
localStorage.setItem("wordsets", JSON.stringify(this.wordsets));
|
|
||||||
localStorage.setItem(id, JSON.stringify([]));
|
|
||||||
this.$router.push('/manage');
|
this.$router.push('/manage');
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
<div class="sidebar-title">
|
<div class="sidebar-title">
|
||||||
|本地
|
|本地
|
||||||
</div>
|
</div>
|
||||||
<div v-for="(set_class, class_name) in wordsets" :title="class_name" :key="class_name"
|
<div v-for="class_name in $store.state.wordsets._allclass" :title="class_name" :key="class_name"
|
||||||
@click="view(class_name)" class="sidebar-item">
|
@click="view(class_name)" class="sidebar-item">
|
||||||
{{ class_name }}
|
{{ class_name }}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
<el-main id="wordsets-container">
|
<el-main id="wordsets-container">
|
||||||
<div id="sets-container">
|
<div id="sets-container">
|
||||||
<div v-if="mode === 0" class="colbox wordclass">
|
<div v-if="mode === 0" class="colbox wordclass">
|
||||||
<div v-for="(wordset, index) in view_wordsets" :key="index" class="wordset rowbox">
|
<div v-for="(wordset, index) in $store.state.wordsets.getClass(view_wordsets)" :key="index" class="wordset rowbox">
|
||||||
<div class="no">
|
<div class="no">
|
||||||
{{ index + 1 }}
|
{{ index + 1 }}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -58,9 +58,9 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="option">
|
<div class="option">
|
||||||
<box-icon class="btn" name='edit' color="var(--text-color)"
|
<box-icon class="btn" name='edit' color="var(--text-color)"
|
||||||
@click="edit(wordset.id, wordset.name)"></box-icon>
|
@click="edit(wordset.id)"></box-icon>
|
||||||
<box-icon class="btn" name='trash' color="var(--text-color)"
|
<box-icon class="btn" name='trash' color="var(--text-color)"
|
||||||
@click="del(view_class, wordset.id, index)"></box-icon>
|
@click="del(view_wordsets, wordset.id, index)"></box-icon>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -95,8 +95,7 @@ export default {
|
||||||
name: "SetList",
|
name: "SetList",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
wordsets: window.wordsets,
|
view_wordsets: "",
|
||||||
view_wordsets: [],
|
|
||||||
viewing: {
|
viewing: {
|
||||||
set: "",
|
set: "",
|
||||||
book: "",
|
book: "",
|
||||||
|
|
@ -108,7 +107,7 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
view(classname) {
|
view(classname) {
|
||||||
this.mode = 0;
|
this.mode = 0;
|
||||||
this.view_wordsets = this.wordsets[classname];
|
this.view_wordsets = classname;
|
||||||
let node = document.getElementById("wordsets-container").style;
|
let node = document.getElementById("wordsets-container").style;
|
||||||
node.animation = "";
|
node.animation = "";
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
@ -127,22 +126,17 @@ export default {
|
||||||
manage_online_wordsets() {
|
manage_online_wordsets() {
|
||||||
window.location.href = '/dashboard';
|
window.location.href = '/dashboard';
|
||||||
},
|
},
|
||||||
del(set_class_name, id, index) {
|
del(class_name, id, index) {
|
||||||
ElMessageBox.confirm("确定要删除吗?")
|
ElMessageBox.confirm("确定要删除吗?")
|
||||||
.then(() => {
|
.then(() => {
|
||||||
localStorage.removeItem(id);
|
this.$store.state.wordsets.delSet(class_name,index);
|
||||||
this.wordsets[set_class_name].splice(index, 1);
|
ElMessage(`已经删除 ${class_name} ${id}`);
|
||||||
if (!this.wordsets[set_class_name].length) {
|
|
||||||
delete this.wordsets[set_class_name];
|
|
||||||
}
|
|
||||||
localStorage.setItem("wordsets", JSON.stringify(this.wordsets));
|
|
||||||
ElMessage(`已经删除 ${set_class_name} `);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
edit(id, name) {
|
edit(id) {
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
path: "./manage/edit",
|
path: "./manage/edit",
|
||||||
query: { id, name }
|
query: { id,classname:this.view_wordsets}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
show(id) {
|
show(id) {
|
||||||
|
|
@ -152,60 +146,22 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
async export_set() {
|
async export_set() {
|
||||||
let fileHandle = await window.showSaveFilePicker({
|
this.$store.state.wordsets.export_set((cnt) => {
|
||||||
types: [
|
ElNotification({
|
||||||
{
|
type: "success",
|
||||||
description: "JSON file",
|
title: "导出成功",
|
||||||
accept: {
|
message: `已导出 ${cnt} 本单词本`
|
||||||
'text/json': ['.json'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
let writestream = await fileHandle.createWritable();
|
})
|
||||||
let data = {
|
|
||||||
wordsets: this.wordsets,
|
|
||||||
words: {}
|
|
||||||
};
|
|
||||||
for (let i of Object.values(this.wordsets)) {
|
|
||||||
for (let j of i) {
|
|
||||||
let temp = localStorage.getItem(j.id);
|
|
||||||
data.words[j.id] = temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
writestream.write(JSON.stringify(data));
|
|
||||||
writestream.close();
|
|
||||||
},
|
},
|
||||||
async import_set() {
|
async import_set() {
|
||||||
let [fileHandle] = await window.showOpenFilePicker({
|
this.$store.state.wordsets.import_set((cnt) => {
|
||||||
types: [
|
|
||||||
{
|
|
||||||
description: "JSON file",
|
|
||||||
accept: {
|
|
||||||
'text/json': ['.json'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
let file = await fileHandle.getFile();
|
|
||||||
let data = JSON.parse(await file.text());
|
|
||||||
let cnt = 0;
|
|
||||||
for (let i of Object.keys(data.wordsets)) {
|
|
||||||
for (let j of data.wordsets[i]) {
|
|
||||||
if (!localStorage.getItem(j.id)) {
|
|
||||||
if (!this.wordsets[i]) this.wordsets[i] = [];
|
|
||||||
this.wordsets[i].push(j);
|
|
||||||
localStorage.setItem(j.id, data.words[j.id]);
|
|
||||||
cnt++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
localStorage.setItem("wordsets", JSON.stringify(this.wordsets));
|
|
||||||
ElNotification({
|
ElNotification({
|
||||||
type: "success",
|
type: "success",
|
||||||
title: "添加成功",
|
title: "添加成功",
|
||||||
message: `已添加 ${cnt} 本单词本`
|
message: `已添加 ${cnt} 本单词本`
|
||||||
});
|
});
|
||||||
|
})
|
||||||
},
|
},
|
||||||
taggle_sidebar() {
|
taggle_sidebar() {
|
||||||
let node = document.getElementById("sidebar");
|
let node = document.getElementById("sidebar");
|
||||||
|
|
@ -215,7 +171,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
let first_set = Object.keys(this.wordsets)[0];
|
let first_set = this.$store.state.wordsets._firstClass;
|
||||||
if (first_set) {
|
if (first_set) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.view(first_set);
|
this.view(first_set);
|
||||||
|
|
@ -258,10 +214,7 @@ export default {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
height: 180px;
|
height: 180px;
|
||||||
width: 40%;
|
width: 40%;
|
||||||
box-shadow: var(--el-box-shadow);
|
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
background-color: var(--bg-color);
|
|
||||||
color: var(--text-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.no {
|
.no {
|
||||||
|
|
@ -323,13 +276,11 @@ export default {
|
||||||
0% {
|
0% {
|
||||||
translate: -100px 0;
|
translate: -100px 0;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
filter: blur(20px);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
translate: 0 0;
|
translate: 0 0;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
filter: blur(0px);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -346,10 +297,7 @@ export default {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
height: 220px;
|
height: 220px;
|
||||||
width: 170px;
|
width: 170px;
|
||||||
box-shadow: var(--el-box-shadow);
|
|
||||||
margin: 20px;
|
margin: 20px;
|
||||||
background-color: var(--bg-color);
|
|
||||||
color: var(--text-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.no {
|
.no {
|
||||||
|
|
@ -378,6 +326,17 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wordset{
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
transition: .5s;
|
||||||
|
border: solid 1px var(--bd-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wordset:hover{
|
||||||
|
box-shadow: var(--el-box-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#sidebar {
|
#sidebar {
|
||||||
|
|
@ -386,6 +345,8 @@ export default {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
animation: sidebar-enter ease-out .6s backwards;
|
animation: sidebar-enter ease-out .6s backwards;
|
||||||
|
height: calc(100% - 50px);
|
||||||
|
margin: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-title {
|
.sidebar-title {
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
mode: 0,
|
mode: 0,
|
||||||
wordsets: window.wordsets,
|
wordsets: this.$store.state.wordsets,
|
||||||
local: {
|
local: {
|
||||||
allsets: [],
|
allsets: [],
|
||||||
checkedSets: [],
|
checkedSets: [],
|
||||||
|
|
@ -153,6 +153,9 @@ export default {
|
||||||
case 'ArrowRight':
|
case 'ArrowRight':
|
||||||
this.next();
|
this.next();
|
||||||
break;
|
break;
|
||||||
|
case 'y':
|
||||||
|
this.audio_play();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -161,14 +164,6 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleCheckAllChange(range, val) {
|
|
||||||
range.checkedSets = val ? range.allsets : [];
|
|
||||||
range.isIndeterminate = false;
|
|
||||||
},
|
|
||||||
handleChange(range, value) {
|
|
||||||
range.checkAll = value.length === range.allsets.length;
|
|
||||||
range.isIndeterminate = value.length > 0 && value.length < range.allsets.length;
|
|
||||||
},
|
|
||||||
async init() {
|
async init() {
|
||||||
if (this.local.checkedSets.length + this.online.checkedSets.length <= 0) {
|
if (this.local.checkedSets.length + this.online.checkedSets.length <= 0) {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
|
|
@ -334,7 +329,14 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
showAnswer() {
|
showAnswer() {
|
||||||
ElMessage(`答案:${this.word.word}`);
|
let e = document.getElementById("input");
|
||||||
|
if(e.value === "_".repeat(this.word.word.length)){
|
||||||
|
e.value = this.word.word[0] + "_".repeat(this.word.word.length-1);
|
||||||
|
e.setSelectionRange(1, 1);
|
||||||
|
ElMessage(`首字母为:${this.word.word[0]}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else ElMessage(`答案:${this.word.word}`);
|
||||||
},
|
},
|
||||||
show() {
|
show() {
|
||||||
this.word = this.testWords[this.seq[this.current]];
|
this.word = this.testWords[this.seq[this.current]];
|
||||||
|
|
@ -350,6 +352,7 @@ export default {
|
||||||
},
|
},
|
||||||
change() {
|
change() {
|
||||||
let e = document.getElementById("input");
|
let e = document.getElementById("input");
|
||||||
|
let cur = e.selectionStart;
|
||||||
let t = e.value, n = t.indexOf("_"), o;
|
let t = e.value, n = t.indexOf("_"), o;
|
||||||
if (n == this.word.word.length) {
|
if (n == this.word.word.length) {
|
||||||
if (t.substring(0, t.length - 1).toLowerCase() == this.word.word.toLowerCase()) {
|
if (t.substring(0, t.length - 1).toLowerCase() == this.word.word.toLowerCase()) {
|
||||||
|
|
@ -369,16 +372,22 @@ export default {
|
||||||
type: "error"
|
type: "error"
|
||||||
});
|
});
|
||||||
o = "_".repeat(this.word.word.length);
|
o = "_".repeat(this.word.word.length);
|
||||||
n = 0;
|
e.value = o;
|
||||||
|
e.setSelectionRange(0, 0);
|
||||||
e.style.height = "0";
|
e.style.height = "0";
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
e.style.height = `${e.scrollHeight}px`;
|
e.style.height = `${e.scrollHeight}px`;
|
||||||
}, 200);
|
}, 200);
|
||||||
} else
|
return;
|
||||||
|
} else{
|
||||||
n == -1 ? o = "_".repeat(this.word.word.length) : (o = t.substring(0, n),
|
n == -1 ? o = "_".repeat(this.word.word.length) : (o = t.substring(0, n),
|
||||||
o += "_".repeat(this.word.word.length - n));
|
o += "_".repeat(this.word.word.length - n));
|
||||||
e.value = o;
|
e.value = o;
|
||||||
|
if(cur > n){
|
||||||
e.setSelectionRange(n, n);
|
e.setSelectionRange(n, n);
|
||||||
|
}
|
||||||
|
else e.setSelectionRange(cur, cur);
|
||||||
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (parseInt(e.style.height) < e.scrollHeight) {
|
if (parseInt(e.style.height) < e.scrollHeight) {
|
||||||
e.style.height = `${e.scrollHeight}px`;
|
e.style.height = `${e.scrollHeight}px`;
|
||||||
|
|
@ -519,7 +528,6 @@ export default {
|
||||||
font-size: 55px;
|
font-size: 55px;
|
||||||
letter-spacing: 15px;
|
letter-spacing: 15px;
|
||||||
min-height: 50px;
|
min-height: 50px;
|
||||||
height: 55px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
|
|
@ -582,9 +590,8 @@ export default {
|
||||||
|
|
||||||
.answer {
|
.answer {
|
||||||
font-size: 70px;
|
font-size: 70px;
|
||||||
letter-spacing: 30px;
|
letter-spacing: 25px;
|
||||||
min-height: 100px;
|
min-height: 100px;
|
||||||
height: 100px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkbox {
|
.checkbox {
|
||||||
|
|
@ -602,13 +609,6 @@ export default {
|
||||||
height: calc(100% - 50px);
|
height: calc(100% - 50px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtitle {
|
|
||||||
font-size: 23px;
|
|
||||||
line-height: 35px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
font-weight: 800;
|
|
||||||
}
|
|
||||||
|
|
||||||
#status {
|
#status {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|
@ -626,15 +626,7 @@ export default {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.set_radios {
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.set_radios p {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 700;
|
|
||||||
color: var(--text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
#lastrecite {
|
#lastrecite {
|
||||||
max-height: 150px;
|
max-height: 150px;
|
||||||
|
|
@ -0,0 +1,301 @@
|
||||||
|
<template>
|
||||||
|
<div class="container" style="width: calc(100% - 60px);align-items: center;display: flex;flex-direction: column">
|
||||||
|
<el-page-header @back="this.$router.push('/manage');" style="width: 100%;">
|
||||||
|
<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) => { handleCheckAllChange(local, res) }" size="large">全选</el-checkbox>
|
||||||
|
<el-checkbox-group v-model="local.checkedSets" @change="(res) => { handleChange(local, res) }">
|
||||||
|
<div class="set_radios" v-for="(set_class, set_class_name) in $store.state.wordsets._inner"
|
||||||
|
:key="set_class_name">
|
||||||
|
<p>{{ 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) => { handleCheckAllChange(online, res) }" size="large">全选</el-checkbox>
|
||||||
|
<el-checkbox-group v-model="online.checkedSets" @change="(res) => { 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>{{ 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>
|
||||||
|
import axios from 'axios';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "SelectPage",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
step: 1,
|
||||||
|
local: {
|
||||||
|
allsets: [],
|
||||||
|
checkedSets: [],
|
||||||
|
isIndeterminate: false,
|
||||||
|
checkAll: false,
|
||||||
|
},
|
||||||
|
online: {
|
||||||
|
allsets: [],
|
||||||
|
checkedSets: [],
|
||||||
|
isIndeterminate: false,
|
||||||
|
checkAll: false,
|
||||||
|
},
|
||||||
|
online_sets: {},
|
||||||
|
online_ids: {},
|
||||||
|
settings: {
|
||||||
|
shuffle: true,
|
||||||
|
direct_answer: false,
|
||||||
|
ignore_phrases: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleCheckAllChange(range, val) {
|
||||||
|
range.checkedSets = val ? range.allsets : [];
|
||||||
|
range.isIndeterminate = false;
|
||||||
|
},
|
||||||
|
handleChange(range, value) {
|
||||||
|
range.checkAll = value.length === range.allsets.length;
|
||||||
|
range.isIndeterminate = value.length > 0 && value.length < range.allsets.length;
|
||||||
|
},
|
||||||
|
completeSelect() {
|
||||||
|
if (this.online.checkedSets.length + this.local.checkedSets.length > 0) {
|
||||||
|
document.getElementById("select-area").style.animation = "exitLeft .25s ease-in forwards";
|
||||||
|
setTimeout(() => {
|
||||||
|
document.getElementById("setting-area").style.animation = "enterRight .25s ease-out forwards";
|
||||||
|
this.step++;
|
||||||
|
}, 250)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ElMessage({
|
||||||
|
type:'error',
|
||||||
|
message:"请选择单词本",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
backSelect() {
|
||||||
|
document.getElementById("setting-area").style.animation = "exitRight .25s ease-in forwards";
|
||||||
|
setTimeout(() => {
|
||||||
|
this.step--;
|
||||||
|
setTimeout(() => {
|
||||||
|
document.getElementById("select-area").style.animation = "enterLeft .25s ease-out forwards";
|
||||||
|
}, 0);
|
||||||
|
}, 250)
|
||||||
|
},
|
||||||
|
startRecite() {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
for (let i of this.$store.state.wordsets._allsets) {
|
||||||
|
for (let j of i) {
|
||||||
|
this.local.allsets.push(j.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.addEventListener('keyup', this.key_listener);
|
||||||
|
axios.get("/wordset/list").then((res, err) => {
|
||||||
|
if (err) {
|
||||||
|
console.log(err);
|
||||||
|
ElMessage({
|
||||||
|
message: "在线词库加载失败",
|
||||||
|
type: "error"
|
||||||
|
})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.online_sets = res.data;
|
||||||
|
for (let i in this.online_sets) {
|
||||||
|
for (let j in this.online_sets[i]) {
|
||||||
|
for (let k in this.online_sets[i][j]) {
|
||||||
|
this.online.allsets.push(k);
|
||||||
|
this.online_ids[k] = {
|
||||||
|
set: i,
|
||||||
|
book: j
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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>
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
const limit = 10;
|
||||||
|
export default class _history{
|
||||||
|
constructor(){
|
||||||
|
this.histories = [];
|
||||||
|
let histories = localStorage.getItem("histories");
|
||||||
|
if (histories) {
|
||||||
|
this.histories = JSON.parse(histories);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
save(){
|
||||||
|
localStorage.setItem('historties',JSON.stringify(this.histories));
|
||||||
|
}
|
||||||
|
get length(){
|
||||||
|
return this.histories.length;
|
||||||
|
}
|
||||||
|
get top(){
|
||||||
|
return this.histories[this.histories.length-1];
|
||||||
|
}
|
||||||
|
use(index) {
|
||||||
|
if(this.histories.length > index){
|
||||||
|
let history = this.histories.splice(index,1);
|
||||||
|
this.histories = [history].concat(this.histories);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
del(index){
|
||||||
|
this.histories.splice(index,1);
|
||||||
|
}
|
||||||
|
add(localsets,onlinesets,settings){
|
||||||
|
let data = {
|
||||||
|
localsets,onlinesets,settings,
|
||||||
|
current:0
|
||||||
|
};
|
||||||
|
if(settings.shuffle){
|
||||||
|
data.settings.seed = (new Date()).getTime();
|
||||||
|
}
|
||||||
|
this.histories = [data].concat(this.histories);
|
||||||
|
}
|
||||||
|
count(){
|
||||||
|
if(this.histories.length>0){
|
||||||
|
this.histories[0].current++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async init_recite(callback){
|
||||||
|
if(typeof callback === 'function'){
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// {"checkedSets":[],"onlineSets":["d8dbc5a0-7d63-11ee-b3a5-cdb8688a6b1b"],"seed":1704712586455}
|
||||||
|
|
@ -0,0 +1,154 @@
|
||||||
|
import uuid from 'node-uuid';
|
||||||
|
|
||||||
|
export default class _wordset {
|
||||||
|
constructor() {
|
||||||
|
this.sets = {};
|
||||||
|
let wordsets = localStorage.getItem("wordsets");
|
||||||
|
if (wordsets) {
|
||||||
|
this.sets = JSON.parse(wordsets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
save() {
|
||||||
|
localStorage.setItem("wordsets", JSON.stringify(this.sets));
|
||||||
|
}
|
||||||
|
get _inner() {
|
||||||
|
return this.sets;
|
||||||
|
}
|
||||||
|
get _firstClass(){
|
||||||
|
return Object.keys(this.sets)[0] || null;
|
||||||
|
}
|
||||||
|
get _allclass(){
|
||||||
|
return Object.keys(this.sets);
|
||||||
|
}
|
||||||
|
get _allsets(){
|
||||||
|
return Object.values(this.sets);
|
||||||
|
}
|
||||||
|
getClass(class_name) {
|
||||||
|
if (this.sets[class_name]) {
|
||||||
|
return this.sets[class_name];
|
||||||
|
}
|
||||||
|
else return null;
|
||||||
|
}
|
||||||
|
getSetStatus(class_name,id){
|
||||||
|
let set_class = this.getClass(class_name);
|
||||||
|
if(set_class){
|
||||||
|
for(let i of set_class){
|
||||||
|
if(i.id === id){
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
getSet(id) {
|
||||||
|
let sets = JSON.parse(localStorage.getItem(id));
|
||||||
|
if (sets) {
|
||||||
|
return sets;
|
||||||
|
}
|
||||||
|
else return [];
|
||||||
|
}
|
||||||
|
delSet(class_name, index) {
|
||||||
|
let set_class = this.sets[class_name];
|
||||||
|
if (set_class) {
|
||||||
|
if (set_class[index]) {
|
||||||
|
localStorage.removeItem(set_class[index].id);
|
||||||
|
this.sets[class_name].splice(index, 1);
|
||||||
|
if (!this.sets[class_name].length) {
|
||||||
|
delete this.sets[class_name];
|
||||||
|
}
|
||||||
|
localStorage.setItem("wordsets", JSON.stringify(this.sets));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
addSet(class_name,name) {
|
||||||
|
if (!this.sets[class_name]) {
|
||||||
|
this.sets[class_name] = [];
|
||||||
|
}
|
||||||
|
let id = uuid.v1();
|
||||||
|
let time = (new Date()).getTime()
|
||||||
|
this.sets[class_name].push({
|
||||||
|
name: name,
|
||||||
|
id: id,
|
||||||
|
created: time,
|
||||||
|
});
|
||||||
|
localStorage.setItem(id, JSON.stringify([]));
|
||||||
|
this.save();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
saveSet(id,data){
|
||||||
|
localStorage.setItem(id, JSON.stringify(data));
|
||||||
|
}
|
||||||
|
renameSet(class_name,id,new_name){
|
||||||
|
let set_class = this.getClass(class_name);
|
||||||
|
if(set_class){
|
||||||
|
for(let i of set_class){
|
||||||
|
if(i.id === id){
|
||||||
|
i.name = new_name;
|
||||||
|
this.save();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async import_set(callback){
|
||||||
|
let [fileHandle] = await window.showOpenFilePicker({
|
||||||
|
types: [
|
||||||
|
{
|
||||||
|
description: "JSON file",
|
||||||
|
accept: {
|
||||||
|
'text/json': ['.json'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
let file = await fileHandle.getFile();
|
||||||
|
let data = JSON.parse(await file.text());
|
||||||
|
let cnt = 0;
|
||||||
|
for (let i of Object.keys(data.wordsets)) {
|
||||||
|
for (let j of data.wordsets[i]) {
|
||||||
|
if (!localStorage.getItem(j.id)) {
|
||||||
|
if (!this.sets[i]) this.sets[i] = [];
|
||||||
|
this.sets[i].push(j);
|
||||||
|
localStorage.setItem(j.id, data.words[j.id]);
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.save();
|
||||||
|
if(typeof callback === "function"){
|
||||||
|
callback(cnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async export_set(callback) {
|
||||||
|
let fileHandle = await window.showSaveFilePicker({
|
||||||
|
types: [
|
||||||
|
{
|
||||||
|
description: "JSON file",
|
||||||
|
accept: {
|
||||||
|
'text/json': ['.json'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
let writestream = await fileHandle.createWritable();
|
||||||
|
let data = {
|
||||||
|
wordsets: this.sets,
|
||||||
|
words: {}
|
||||||
|
};
|
||||||
|
let cnt = 0;
|
||||||
|
for (let i of Object.values(this.sets)) {
|
||||||
|
for (let j of i) {
|
||||||
|
let temp = localStorage.getItem(j.id);
|
||||||
|
data.words[j.id] = temp;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writestream.write(JSON.stringify(data));
|
||||||
|
writestream.close();
|
||||||
|
if(typeof callback === "function"){
|
||||||
|
callback(cnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,13 +2,15 @@ import {createRouter,createWebHashHistory} from 'vue-router'
|
||||||
const manage = ()=>import('./components/Manage.vue');
|
const manage = ()=>import('./components/Manage.vue');
|
||||||
const editor = ()=>import('./components/manage/Editor.vue');
|
const editor = ()=>import('./components/manage/Editor.vue');
|
||||||
const home = ()=>import("./components/Home.vue");
|
const home = ()=>import("./components/Home.vue");
|
||||||
const recite = ()=>import('./components/Recite.vue');
|
const recite = ()=>import('./components/recite/recite.vue');
|
||||||
const setlist = ()=>import('./components/manage/SetList.vue');
|
const setlist = ()=>import('./components/manage/SetList.vue');
|
||||||
const newset = ()=>import('./components/manage/NewSet.vue');
|
const newset = ()=>import('./components/manage/NewSet.vue');
|
||||||
const display = ()=>import('./components/manage/Display.vue');
|
const display = ()=>import('./components/manage/Display.vue');
|
||||||
|
const select = ()=>import('./components/recite/select.vue')
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{ path: '/', component: home },
|
{ path: '/', component: home },
|
||||||
|
{ path: '/select',component:select},
|
||||||
{ path:'/recite',component:recite},
|
{ path:'/recite',component:recite},
|
||||||
{ path: '/manage', component: manage,
|
{ path: '/manage', component: manage,
|
||||||
children:[
|
children:[
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue