Compare commits

...

4 Commits

Author SHA1 Message Date
cast1e 9ad162a5b9 beta2 2024-04-12 12:41:02 +08:00
cast1e a4a5e7ce9b wordset-managing functions 2024-04-12 09:52:25 +08:00
cast1e 34ad23db7a bug fixes 2024-04-02 21:03:03 +08:00
cast1e 585ed83a3f Patch 1 2024-01-14 17:50:25 +08:00
16 changed files with 541 additions and 196 deletions

55
package-lock.json generated
View File

@ -26,8 +26,7 @@
"@vue/cli-service": "~5.0.0", "@vue/cli-service": "~5.0.0",
"element-plus": "^2.3.14", "element-plus": "^2.3.14",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3", "eslint-plugin-vue": "^8.0.3"
"raw-loader": "^4.0.2"
} }
}, },
"node_modules/@aashutoshrathi/word-wrap": { "node_modules/@aashutoshrathi/word-wrap": {
@ -9331,58 +9330,6 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/raw-loader": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz",
"integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==",
"dev": true,
"dependencies": {
"loader-utils": "^2.0.0",
"schema-utils": "^3.0.0"
},
"engines": {
"node": ">= 10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependencies": {
"webpack": "^4.0.0 || ^5.0.0"
}
},
"node_modules/raw-loader/node_modules/loader-utils": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
"dev": true,
"dependencies": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
},
"engines": {
"node": ">=8.9.0"
}
},
"node_modules/raw-loader/node_modules/schema-utils": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
"integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
"dev": true,
"dependencies": {
"@types/json-schema": "^7.0.8",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
},
"engines": {
"node": ">= 10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
}
},
"node_modules/react": { "node_modules/react": {
"version": "16.14.0", "version": "16.14.0",
"resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",

View File

@ -26,8 +26,7 @@
"@vue/cli-service": "~5.0.0", "@vue/cli-service": "~5.0.0",
"element-plus": "^2.3.14", "element-plus": "^2.3.14",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3", "eslint-plugin-vue": "^8.0.3"
"raw-loader": "^4.0.2"
}, },
"eslintConfig": { "eslintConfig": {
"root": true, "root": true,

View File

@ -1,13 +1,23 @@
<template> <template>
<div id="navibar" class="pconly" > <div class="pconly">
<div class="navi-item"><el-link @click="go('/')" id="logo">wordIn</el-link></div> <div id="navibar">
<div class="navi-item"><el-link @click="go('/select')" class="link">背诵</el-link></div> <div class="navi-item"><el-link @click="go('/')" id="logo">wordIn</el-link></div>
<div class="navi-item"><el-link @click="go('/manage')" class="link">编辑单词本</el-link></div> <div class="navi-item"><el-link @click="go('/select')" class="link">背诵</el-link></div>
<div class="navi-item"><el-link @click="go('/manual')" class="link">使用说明</el-link></div> <div class="navi-item"><el-link @click="go('/manage')" class="link">编辑单词本</el-link></div>
<div class="navi-item"><el-link @click="go('/about')" class="link">关于</el-link></div> <div class="navi-item"><el-link @click="go('/manual')" class="link">使用说明</el-link></div>
<div class="navi-item"><el-link @click="go('/about')" class="link">关于</el-link></div>
</div>
</div>
<router-view style=""></router-view>
<div class="mbonly">
<div id="navibar">
<div class="navi-item"><box-icon name="home-alt-2" @click="$router.push('/')" color="var(--text-color)" size="27px"></box-icon><div></div></div>
<div class="navi-item"><box-icon name="book-open" @click="$router.push('/select')" color="var(--text-color)" size="27px"></box-icon><div></div></div>
<div class="navi-item"><box-icon name="folder" @click="$router.push('/manage')" color="var(--text-color)" size="27px"></box-icon><div></div></div>
<div class="navi-item"><box-icon name="file" @click="$router.push('/manual')" color="var(--text-color)" size="27px"></box-icon><div></div></div>
<div class="navi-item"><box-icon name="info-circle" @click="$router.push('/about')" color="var(--text-color)" size="27px"></box-icon><div></div></div>
</div>
</div> </div>
<router-view style="margin-top: 10px;"></router-view>
<!-- <div id="navibar" class="mbonly"></div> -->
</template> </template>
<script> <script>
@ -106,13 +116,19 @@ export default {
} }
} }
#app{
transition: .5s;
}
html { html {
--bg-color-solid:#e8e8e8;
--bg-color: #ffffffae; --bg-color: #ffffffae;
--text-color: #464646; --text-color: #464646;
--bd-color: #bbbbbb99; --bd-color: #bbbbbb99;
} }
html.dark { html.dark {
--bg-color-solid:#191919;
--bg-color: #2a2a2a88; --bg-color: #2a2a2a88;
--text-color: #c0c0c0; --text-color: #c0c0c0;
--bd-color: #7f7f7f7c; --bd-color: #7f7f7f7c;
@ -144,7 +160,8 @@ html.dark {
color: var(--text-color); color: var(--text-color);
transition: .5s; transition: .5s;
} }
.card:hover{
.card:hover {
box-shadow: var(--el-box-shadow); box-shadow: var(--el-box-shadow);
} }
@ -168,25 +185,57 @@ html.bgimged .card {
.para { .para {
margin: 15px; margin: 15px;
} }
.blured {
filter: blur(10px);
}
</style> </style>
<style scoped> <style scoped>
#navibar { @media screen and (max-width: 500px) {
height: 60px; #navibar {
border-bottom: solid 1px var(--bd-color); height: 55px;
display: flex; border-top: solid 1px var(--bd-color);
flex-direction: row; display: flex;
background-color: var(--navi-bg-color); flex-direction: row;
backdrop-filter: blur(10px); justify-content: space-around;
background-color: var(--navi-bg-color);
backdrop-filter: blur(10px);
position: absolute;
bottom: 0;
width: 100%;
}
.navi-item {
height: 100%;
font-size: 11px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
justify-content: baseline;
color: var(--text-color);
}
} }
.navi-item { @media screen and (min-width: 500px) {
height: 100%; #navibar {
font-size: 22px; height: 60px;
display: flex; border-bottom: solid 1px var(--bd-color);
justify-content: baseline; display: flex;
margin-left: 20px; flex-direction: row;
color: var(--text-color); 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 { #logo {

View File

@ -4,7 +4,7 @@
<div style="flex-grow: 2;margin:30px;" class="rowbox"> <div style="flex-grow: 2;margin:30px;" class="rowbox">
<div style="font-size: 25px;color: var(--text-color);font-weight: 600;">欢迎使用</div> <div style="font-size: 25px;color: var(--text-color);font-weight: 600;">欢迎使用</div>
<div id="title">wordIn</div> <div id="title">wordIn</div>
<div>当前版本: 1.01 更新时间:2024年1月11日 10:43 AM</div> <div>当前版本: 1.02 Beta 2 <br/> 更新时间:2024年1月11日 5:07 PM</div>
</div> </div>
<div style="flex-grow: 1;align-items: center;" class="colbox card"> <div style="flex-grow: 1;align-items: center;" class="colbox card">
<router-link to="/select" class="button"> <router-link to="/select" class="button">
@ -122,12 +122,12 @@ export default {
color: var(--text-color); color: var(--text-color);
text-shadow: #00000057 5px 5px 20px; text-shadow: #00000057 5px 5px 20px;
line-height: 100px; line-height: 100px;
font-weight: 600; font-weight: 500;
margin-bottom: 15px; margin-bottom: 15px;
} }
.title { .title {
font-weight: 800; font-weight: 600;
color: var(--text-color); color: var(--text-color);
font-size: 35px; font-size: 35px;
text-overflow: ellipsis; text-overflow: ellipsis;

View File

@ -0,0 +1,96 @@
<template>
<div id="mask" v-if="visible">
<div ref="bg" id="bg">
<div id="content">
<slot name="content"></slot>
</div>
<div id="close" @click="handleClose"><box-icon color="var(--text-color)" size="20px" name="x"></box-icon></div>
</div>
</div>
</template>
<script>
export default {
name:"CDiaLog",
props:{
"visible":{
type:Boolean,
default:false
}
},
methods:{
handleClose(){
this.$refs.bg.style.animation = "cui-dialog-disappear .3s ease-in";
setTimeout(()=>this.$emit("update:visible",false),300);
}
}
}
</script>
<style>
@keyframes cui-dialog-appear {
0%{
opacity: 0%;
transform: translate(-50%,-50%) scale(0.5);
}
100%{
opacity: 100%;
transform: translate(-50%,-50%) scale(1);
}
}
@keyframes cui-dialog-disappear {
0%{
opacity: 100%;
transform: translate(-50%,-50%) scale(1);
}
100%{
opacity: 0%;
transform: translate(-50%,-50%) scale(0.5);
}
}
@keyframes cui-dialog-blur{
0%{
backdrop-filter:blur(0px);
}
100%{
backdrop-filter:blur(10px);
}
}
</style>
<style scoped>
#mask{
z-index: 500;
position: absolute;
top:0;
left: 0;
width: 100%;
height: 100%;
backdrop-filter: blur(10px);
animation: cui-dialog-blur .5s ;
}
#bg{
position: absolute;
width: 500px;
height: 300px;
max-width: 80%;
border: solid var(--bd-color) 1px;
background-color: var(--bg-color-solid);
border-radius: 8px;
transform: translate(-50%,-50%);
top: 50%;
left: 50%;
animation: cui-dialog-appear .4s cubic-bezier(0, 0, 0.36, 1.29);
}
#content{
padding: 20px;
height: 100%;
}
#close{
position: absolute;
right:0;
top: 0;
margin: 5px;
cursor: pointer;
}
</style>

View File

@ -4,6 +4,19 @@
<template #content> <template #content>
<span class="text-large font-600 mr-3"> {{ set }} : {{ book }} ({{ id }}) </span> <span class="text-large font-600 mr-3"> {{ set }} : {{ book }} ({{ id }}) </span>
</template> </template>
<template #extra>
<el-dropdown trigger="click">
<el-button>
操作<box-icon color="var(--text-color)" name='chevron-down' size="20px"></box-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="download"><box-icon color="var(--text-color)" name='download'
size="20px"></box-icon></el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</el-page-header> </el-page-header>
<div class="colbox" id="main"> <div class="colbox" id="main">
<div style="flex-grow: 1;" class="card"> <div style="flex-grow: 1;" class="card">
@ -19,8 +32,7 @@
</template> </template>
<script> <script>
import { ElMessage } from 'element-plus';
import axios from 'axios';
export default { export default {
name: "NoteEditor", name: "NoteEditor",
@ -29,12 +41,19 @@ export default {
table: [], table: [],
} }
}, },
methods:{
download(){
this.$store.state.wordsets.fromArray(this.table,this.book,this.name);
ElMessage("下载完毕");
}
},
created() { created() {
this.set = this.$route.query.set; this.set = this.$route.query.set;
this.book = this.$route.query.book; this.book = this.$route.query.book;
this.id = this.$route.query.id; this.id = this.$route.query.id;
this.name = this.$route.query.name || "default";
if (this.set && this.book && this.id) { if (this.set && this.book && this.id) {
axios.get("./wordset/detail", { this.$axios.get("wordset/detail", {
params:{ params:{
set: this.set, book: this.book, id: this.id set: this.set, book: this.book, id: this.id
} }

View File

@ -1,15 +1,31 @@
<template> <template>
<div class="container" style="overflow: auto;"> <div class="container" style="overflow: auto;">
<el-page-header style="margin: 10px;" @back="this.$router.push('/manage');"> <el-page-header style="margin: 10px;" @back="this.$router.push('/manage');">
<template #content> <template #content>
<span class="text-large font-600 mr-3"> {{ name }} ({{ id }}) </span> <span class="text-large font-600 mr-3"> {{ name }} ({{ id }}) </span>
</template> </template>
<template #extra>
<el-dropdown trigger="click">
<el-button>
操作<box-icon color="var(--text-color)" name='chevron-down' size="20px"></box-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="del_set"><box-icon color="var(--text-color)" name='trash'
size="20px"></box-icon></el-dropdown-item>
<el-dropdown-item @click="addTo"><box-icon color="var(--text-color)" name='plus'
size="18px"></box-icon></el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</el-page-header> </el-page-header>
<div class="colbox" id="main"> <div class="colbox" id="main">
<div class="rowbox"> <div class="rowbox">
<div class="card"> <div class="card">
<div class="title">添加单词</div> <div class="title">添加单词</div>
<el-input ref="input1" autofocus @change="focusnext($refs.input2)" v-model="new_word.word"></el-input> <el-input ref="input1" autofocus @change="focusnext($refs.input2)"
v-model="new_word.word"></el-input>
<div class="colbox"> <div class="colbox">
<el-text class="mx-1" style="width: 60px;">翻译:</el-text> <el-text class="mx-1" style="width: 60px;">翻译:</el-text>
<el-input ref="input2" @change="focusnext($refs.input3)" v-model="new_word.trans"></el-input> <el-input ref="input2" @change="focusnext($refs.input3)" v-model="new_word.trans"></el-input>
@ -17,7 +33,8 @@
<div class="colbox"> <div class="colbox">
<el-text class="mx-1" style="width: 80px;">词性</el-text> <el-text class="mx-1" style="width: 80px;">词性</el-text>
<el-select ref="input3" v-model="new_word.type" class="m-2" placeholder="Select"> <el-select ref="input3" v-model="new_word.type" class="m-2" placeholder="Select">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in options" :key="item.value" :label="item.label"
:value="item.value" />
</el-select> </el-select>
</div> </div>
<el-button @click="add_word()" type="primary">添加</el-button> <el-button @click="add_word()" type="primary">添加</el-button>
@ -51,28 +68,54 @@
</div> </div>
</div> </div>
</div> </div>
<el-dialog v-model="word_editing" width="80%"> <CDialog v-model:visible="word_editing">
<div class="title">修改单词</div> <template #content>
<el-input v-model="editing_word.word"></el-input> <div class="title">修改单词</div>
<div class="colbox"> <el-input v-model="editing_word.word"></el-input>
<el-text class="mx-1" style="width: 60px;">翻译:</el-text> <div class="colbox">
<el-input v-model="editing_word.trans"></el-input> <el-text class="mx-1" style="width: 60px;">翻译:</el-text>
</div> <el-input v-model="editing_word.trans"></el-input>
<div class="colbox"> </div>
<el-text class="mx-1" style="width: 80px;">词性</el-text> <div class="colbox">
<el-select v-model="editing_word.type" class="m-2" placeholder="Select"> <el-text class="mx-1" style="width: 80px;">词性</el-text>
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> <el-select v-model="editing_word.type" class="m-2" placeholder="Select">
</el-select> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</div> </el-select>
<el-button @click="save_word" type="primary">更改</el-button> </div>
</el-dialog> <el-button @click="save_word" type="primary">更改</el-button>
</template>
</CDialog>
<CDialog v-model:visible="select.visible">
<template #content>
<el-text class="mx-1 title">选择加入的单词本</el-text>
<div class="colbox para">
<div class="mid-text">分组:</div>
<el-select v-model="select.set_class" class="m-2" placeholder="Select">
<el-option v-for="item in $store.state.wordsets._allclass" :key="item" :label="item"
:value="item" />
</el-select>
</div>
<div class="colbox para">
<div class="mid-text">单词本:</div>
<el-select v-model="select.id" class="m-2" placeholder="Select">
<el-option v-for="item in $store.state.wordsets.getClass(select.set_class)" :key="item.id"
:label="item.name" :value="item.id" />
</el-select>
</div>
<el-button @click="select.confirm(select.id)" type="primary">确认</el-button>
</template>
</CDialog>
</template> </template>
<script> <script>
import { ElMessage } from 'element-plus'; import { ElMessage, ElMessageBox } from 'element-plus';
import CDialog from '../UI/CDialog.vue'
export default { export default {
name: "NoteEditor", name: "NoteEditor",
components: {
CDialog
},
data() { data() {
return { return {
new_word: { new_word: {
@ -90,8 +133,13 @@ export default {
table: [], table: [],
word_editing: false, word_editing: false,
new_name: "", new_name: "",
name:"", name: "",
id:"" id: "",
select: {
visible: false,
set_class: "",
id: ""
}
} }
}, },
methods: { methods: {
@ -113,7 +161,7 @@ export default {
return; return;
} }
this.table.push(Object.assign({}, this.new_word)); this.table.push(Object.assign({}, this.new_word));
this.$store.state.wordsets.saveSet(this.id,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',
@ -143,7 +191,7 @@ export default {
type: this.editing_word.type, type: this.editing_word.type,
trans: this.editing_word.trans, trans: this.editing_word.trans,
} }
this.$store.state.wordsets.saveSet(this.id,this.table); this.$store.state.wordsets.saveSet(this.id, this.table);
ElMessage({ ElMessage({
message: `已保存更改`, message: `已保存更改`,
type: 'success', type: 'success',
@ -153,7 +201,7 @@ export default {
change_name() { change_name() {
let old_name = this.name; let old_name = this.name;
this.name = this.new_name; this.name = this.new_name;
this.$store.state.wordsets.renameSet(this.class_name,this.id,this.new_name); this.$store.state.wordsets.renameSet(this.class_name, this.id, this.new_name);
ElMessage({ ElMessage({
message: `已更改 ${old_name}${this.name}`, message: `已更改 ${old_name}${this.name}`,
type: 'success', type: 'success',
@ -163,20 +211,42 @@ 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);
this.$store.state.wordsets.saveSet(this.id,this.table); this.$store.state.wordsets.saveSet(this.id, this.table);
ElMessage({ ElMessage({
message: `已删除 ${word}`, message: `已删除 ${word}`,
type: 'warning', type: 'warning',
}); });
}, },
del_set() {
ElMessageBox.confirm("确定要删除吗?")
.then(() => {
let index = this.$store.state.wordsets.getId(this.class_name, this.id);
this.$store.state.wordsets.delSet(this.class_name, index);
ElMessage(`已经删除 ${this.class_name} ${this.id}`);
this.$router.push("/manage");
});
},
addTo() {
this.select.visible = true;
this.select.confirm = (dest_id) => {
if (this.id) {
if(this.id != dest_id){
let failed = this.$store.state.wordsets.addSetTo(this.id, dest_id);
ElMessage(`已经添加到 ${dest_id}, 已经去除 ${failed} 个重复单词`);
}
else ElMessage(`请选择一个不同的单词本`);
}
this.select.visible = false;
}
},
}, },
created() { created() {
this.class_name = this.$route.query.classname; this.class_name = this.$route.query.classname;
this.id = this.$route.query.id; this.id = this.$route.query.id;
if(this.id){ if (this.id) {
let status = this.$store.state.wordsets.getSetStatus(this.class_name,this.id); let status = this.$store.state.wordsets.getSetStatus(this.class_name, this.id);
if(status){ if (status) {
this.name = status.name; this.name = status.name;
} }
this.table = this.$store.state.wordsets.getSet(this.id); this.table = this.$store.state.wordsets.getSet(this.id);
@ -187,31 +257,31 @@ export default {
<style scoped> <style scoped>
@media screen and (max-width: 500px) { @media screen and (max-width: 500px) {
#main{ #main {
flex-direction: column; flex-direction: column;
overflow: scroll; overflow: scroll;
} }
.title{ .title {
font-size: 25px; font-size: 25px;
min-height: 50px; min-height: 50px;
} }
} }
@media screen and (min-width: 500px) { @media screen and (min-width: 500px) {
.title{ .title {
font-size: 35px; font-size: 35px;
min-height: 60px; min-height: 60px;
} }
.container{ .container {
padding: 10px; padding: 10px;
height: calc(100% - 70px); height: calc(100% - 70px);
padding-top: 0; padding-top: 0;
} }
} }
#main{ #main {
height: calc(100% - 50px); height: calc(100% - 50px);
} }

View File

@ -6,46 +6,61 @@
<span class="text-large font-600 mr-3"> 编辑单词本 </span> <span class="text-large font-600 mr-3"> 编辑单词本 </span>
</template> </template>
<template #extra> <template #extra>
<div class="pconly"> <div class="colbox">
<el-button @click="manage_online_wordsets" type="primary"><box-icon color="white" name='world' <el-button @click="$router.push('/manage/new')" type="success"><box-icon color="white"
size="20px"></box-icon>线</el-button>
<el-button @click="export_set" type="success"><box-icon color="white" name='export'
size="18px"></box-icon></el-button>
<el-button @click="import_set" type="warning"><box-icon color="white" name='import'
size="18px"></box-icon></el-button>
<el-button @click="$router.push('/manage/new')" type="primary"><box-icon color="white"
name='plus'></box-icon></el-button> name='plus'></box-icon></el-button>
<div class="pconly">
<el-dropdown trigger="click" style="margin-left: 20px;">
<el-button type="primary">
更多<box-icon color="white" name='chevron-down' size="20px"></box-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="manage_online_wordsets"><box-icon color="white"
name='world' size="20px"></box-icon>线</el-dropdown-item>
<el-dropdown-item @click="export_set"><box-icon color="white" name='export'
size="18px"></box-icon></el-dropdown-item>
<el-dropdown-item @click="import_set"><box-icon color="white" name='import'
size="18px"></box-icon></el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div> </div>
</template> </template>
</el-page-header> </el-page-header>
<div class="mbonly">
<el-button @click="$router.push('/manage/new')" type="primary"><box-icon color="white"
name='plus'></box-icon></el-button>
</div>
</el-header> </el-header>
<el-container style="height:calc(100% - 200px);position: relative;"> <el-container style="height:calc(100% - 200px);position: relative;">
<el-aside id="sidebar"> <el-aside id="aside">
<div class="sidebar-title"> <div id="sidebar" class="sidebar-hidden">
|本地 <div id="sidebar-content">
</div> <div class="sidebar-title">
<div v-for="class_name in $store.state.wordsets._allclass" :title="class_name" :key="class_name" |本地
@click="view(class_name)" class="sidebar-item"> </div>
{{ class_name }} <div v-for="class_name in $store.state.wordsets._allclass" :title="class_name" :key="class_name"
</div> @click="view(class_name)" class="sidebar-item">
<div class="sidebar-title"> {{ class_name }}
|在线 </div>
</div> <div class="sidebar-title">
<div v-for="set in Object.keys(online_wordsets)" :key="set"> |在线
<div v-for="(set_class, class_name) in online_wordsets[set]" :title="class_name" :key="class_name" </div>
@click="view_online(set, class_name)" class="sidebar-item"> <div v-for="set in Object.keys(online_wordsets)" :key="set">
{{ class_name }} <div v-for="(set_class, class_name) in online_wordsets[set]" :title="class_name"
:key="class_name" @click="view_online(set, class_name)" class="sidebar-item">
{{ class_name }}
</div>
</div>
</div>
<div class="mbonly" id="show-sidebar" @click="taggle_sidebar">
<box-icon name='list-ul' color="var(--text-color)"></box-icon>
</div> </div>
</div> </div>
</el-aside> </el-aside>
<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 $store.state.wordsets.getClass(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>
@ -73,14 +88,12 @@
创建日期{{ (new Date(wordset.created)).toLocaleString() }} 创建日期{{ (new Date(wordset.created)).toLocaleString() }}
</div> </div>
<div class="option"> <div class="option">
<box-icon class="btn" name='show' color="var(--text-color)" @click="show(index)"></box-icon> <box-icon class="btn" name='show' color="var(--text-color)"
@click="show(index, wordset.name)"></box-icon>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="mbonly" id="show-sidebar" @click="taggle_sidebar">
<box-icon name='list-ul' color="var(--text-color)"></box-icon>
</div>
</el-main> </el-main>
</el-container> </el-container>
</el-container> </el-container>
@ -88,7 +101,6 @@
<script> <script>
import { ElNotification, ElMessage, ElMessageBox } from 'element-plus'; import { ElNotification, ElMessage, ElMessageBox } from 'element-plus';
import axios from 'axios';
export default { export default {
name: "SetList", name: "SetList",
@ -128,20 +140,20 @@ export default {
del(class_name, id, index) { del(class_name, id, index) {
ElMessageBox.confirm("确定要删除吗?") ElMessageBox.confirm("确定要删除吗?")
.then(() => { .then(() => {
this.$store.state.wordsets.delSet(class_name,index); this.$store.state.wordsets.delSet(class_name, index);
ElMessage(`已经删除 ${class_name} ${id}`); ElMessage(`已经删除 ${class_name} ${id}`);
}); });
}, },
edit(id) { edit(id) {
this.$router.push({ this.$router.push({
path: "./manage/edit", path: "./manage/edit",
query: { id,classname:this.view_wordsets} query: { id, classname: this.view_wordsets }
}) })
}, },
show(id) { show(id, name) {
this.$router.push({ this.$router.push({
path: "./manage/show", path: "./manage/show",
query: { set: this.viewing.set, book: this.viewing.book, id } query: { set: this.viewing.set, book: this.viewing.book, id, name }
}) })
}, },
async export_set() { async export_set() {
@ -164,8 +176,11 @@ export default {
}, },
taggle_sidebar() { taggle_sidebar() {
let node = document.getElementById("sidebar"); let node = document.getElementById("sidebar");
if (node.style.width === "180px") node.style.width = "0"; let class_name = "sidebar-hidden";
else node.style.width = "180px"; if(node.classList.contains(class_name)){
node.classList.remove(class_name);
}
else node.classList.add(class_name);
return; return;
} }
}, },
@ -176,7 +191,7 @@ export default {
this.view(first_set); this.view(first_set);
}, 0); }, 0);
} }
axios.get("/wordset/list").then( this.$axios.get("wordset/list").then(
(res) => { (res) => {
this.online_wordsets = res.data; this.online_wordsets = res.data;
} }
@ -203,9 +218,21 @@ export default {
height: 70px; height: 70px;
} }
#sidebar { #aside {
width: 0; width: 0;
position: relative;
}
#sidebar {
position: absolute;
width: 180px;
margin-top: 20px;
transition: .5s; transition: .5s;
z-index: 100;
}
.sidebar-hidden{
transform: translate(-100%,0);
} }
.wordset { .wordset {
@ -243,6 +270,7 @@ export default {
} }
#show-sidebar { #show-sidebar {
position: absolute;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
@ -250,9 +278,8 @@ export default {
border-radius: 100%; border-radius: 100%;
width: 40px; width: 40px;
height: 40px; height: 40px;
position: absolute; bottom: 0;
bottom: 20px; right: -50px;
left: 20px;
color: var(--text-color); color: var(--text-color);
box-shadow: var(--el-box-shadow); box-shadow: var(--el-box-shadow);
background-color: var(--bg-color); background-color: var(--bg-color);
@ -263,6 +290,7 @@ export default {
#wordsets-container { #wordsets-container {
width: 100%; width: 100%;
display: flex; display: flex;
transition: .5s;
} }
#sets-container { #sets-container {
@ -287,8 +315,15 @@ export default {
height: 60px; height: 60px;
} }
#aside {
width:180px;
}
#sidebar { #sidebar {
width: 180px; width: 180px;
animation: sidebar-enter ease-out .6s backwards;
padding-left: 10px;
margin: 10px;
} }
.wordset { .wordset {
@ -325,29 +360,30 @@ export default {
} }
} }
.wordset{ .wordset {
background-color: var(--bg-color); background-color: var(--bg-color);
color: var(--text-color); color: var(--text-color);
transition: .5s; transition: .5s;
border: solid 1px var(--bd-color); border: solid 1px var(--bd-color);
} }
.wordset:hover{ .wordset:hover {
box-shadow: var(--el-box-shadow); box-shadow: var(--el-box-shadow);
} }
#sidebar { #sidebar {
background-color: var(--bg-color); background-color: var(--bg-color-solid);
border-radius: 5px; border-radius: 5px;
height: calc(100% - 100px);
border: 1px solid var(--bd-color);
transition: .5s;
}
#sidebar-content{
width: 100%;
height: 100%;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
animation: sidebar-enter ease-out .6s backwards;
height: calc(100% - 100px);
padding-left: 10px;
margin: 10px;
border: 1px solid var(--bd-color);
} }
.sidebar-title { .sidebar-title {
@ -418,4 +454,8 @@ html.bgimged .wordset {
--el-collapse-content-bg-color: #FFFFFF00; --el-collapse-content-bg-color: #FFFFFF00;
--el-collapse-header-font-size: 18px; --el-collapse-header-font-size: 18px;
} }
.el-aside {
overflow: visible;
}
</style> </style>

View File

@ -83,7 +83,6 @@
</template> </template>
<script> <script>
import axios from 'axios';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
export default { export default {
@ -161,7 +160,7 @@ export default {
} }
} }
document.addEventListener('keyup', this.key_listener); document.addEventListener('keyup', this.key_listener);
axios.get("/wordset/list").then((res, err) => { this.$axios.get("wordset/list").then((res, err) => {
if (err) { if (err) {
ElMessage({ ElMessage({
message: "在线词库加载失败", message: "在线词库加载失败",
@ -207,7 +206,8 @@ export default {
/* margin: 20px; */ /* margin: 20px; */
align-items: center; align-items: center;
display: flex; display: flex;
flex-direction: column flex-direction: column;
margin-top:10px;
} }
.subtitle { .subtitle {
font-size: 23px; font-size: 23px;

View File

@ -1,4 +1,4 @@
import axios from 'axios' import axios from './request.js'
const limit = 10; const limit = 10;
export default class _history { export default class _history {
constructor() { constructor() {
@ -81,7 +81,7 @@ export default class _history {
else return this.handle_err("单词本不存在",err); else return this.handle_err("单词本不存在",err);
} }
for (let i of history.onlinesets) { for (let i of history.onlinesets) {
let res = await axios.get("/wordset/detail", { let res = await axios.get("wordset/detail", {
params: i params: i
}) })
if (res.status != 200) { if (res.status != 200) {
@ -97,17 +97,17 @@ export default class _history {
} }
else words = words.concat(...temp); else words = words.concat(...temp);
} }
let arr = Array.from(new Array(words.length).keys()); history.total = words.length;
if(history.settings.shuffle){
let seed = history.settings.seed;
for (let i = this.total - 1; i > 0; i--) {
[arr[i], arr[seed % i]] = [arr[seed % i], arr[i]];
}
}
if(words.length <= 0){ if(words.length <= 0){
return this.handle_err("单词本为空",err); return this.handle_err("单词本为空",err);
} }
history.total = words.length; let arr = Array.from(new Array(words.length).keys());
if(history.settings.shuffle){
let seed = history.settings.seed;
for (let i = words.length - 1; i > 0; i--) {
[arr[i], arr[seed % i]] = [arr[seed % i], arr[i]];
}
}
this.save(); this.save();
if (typeof callback === 'function') { if (typeof callback === 'function') {
callback(words,history.current,arr,history.settings); callback(words,history.current,arr,history.settings);

View File

@ -0,0 +1,8 @@
import axios from 'axios'
const instance = axios.create({
baseURL:"./",
timeout:6000,
})
export default instance;

View File

@ -1,5 +1,6 @@
import uuid from 'node-uuid'; import uuid from 'node-uuid';
export default class _wordset { export default class _wordset {
constructor() { constructor() {
this.sets = {}; this.sets = {};
@ -40,6 +41,14 @@ export default class _wordset {
} }
return null; return null;
} }
getId(class_name,id){
let set_class = this.sets[class_name];
for(let index in set_class){
if(set_class[index].id === id){
return index;
}
}
}
getSet(id) { getSet(id) {
let sets = JSON.parse(localStorage.getItem(id)); let sets = JSON.parse(localStorage.getItem(id));
if (sets) { if (sets) {
@ -75,7 +84,7 @@ export default class _wordset {
}); });
localStorage.setItem(id, JSON.stringify([])); localStorage.setItem(id, JSON.stringify([]));
this.save(); this.save();
return; return id;
} }
saveSet(id,data){ saveSet(id,data){
localStorage.setItem(id, JSON.stringify(data)); localStorage.setItem(id, JSON.stringify(data));
@ -92,6 +101,24 @@ export default class _wordset {
} }
} }
} }
addSetTo(origin_id,dest_id){
let origin_set = this.getSet(origin_id);
let dest_set = this.getSet(dest_id);
let set={};
origin_set.forEach(element => {
set[element.word] = element;
});
dest_set.forEach(element => {
set[element.word] = element;
});
set = Object.values(set);
this.saveSet(dest_id,set);
return origin_set.length + dest_set.length - set.length;
}
fromArray(arr,class_name,name){
let id = this.addSet(class_name,name);
this.saveSet(id,arr);
}
async import_set(callback){ async import_set(callback){
let [fileHandle] = await window.showOpenFilePicker({ let [fileHandle] = await window.showOpenFilePicker({
types: [ types: [

View File

@ -0,0 +1,53 @@
import {
ElForm,
ElButton,
ElInput,
ElCheckbox,
ElDialog,
ElTable,
ElStep,
ElLink,
ElCard,
ElCheckboxGroup,
ElDropdown,
ElFooter,
ElMain,
ElContainer,
ElHeader,
ElPageHeader,
ElTabs,
ElTabPane,
ElSteps,
ElSwitch,
ElSelect,
ElOption,
} from 'element-plus'
const element = {
install: function(app) {
app.use(ElForm)
app.use(ElButton)
app.use(ElInput)
app.use(ElCheckbox)
app.use(ElDialog)
app.use(ElTable)
app.use(ElStep)
app.use(ElLink)
app.use(ElCard)
app.use(ElCheckboxGroup)
app.use(ElDropdown)
app.use(ElFooter)
app.use(ElMain)
app.use(ElContainer)
app.use(ElHeader)
app.use(ElPageHeader)
app.use(ElTabPane)
app.use(ElSteps)
app.use(ElTabs)
app.use(ElSwitch)
app.use(ElSelect)
app.use(ElOption)
}
}
export default element

View File

@ -1,11 +1,13 @@
import { createApp } from 'vue' import {createApp} from 'vue'
import App from './App.vue' import App from './App.vue'
import { createStore } from 'vuex' import { createStore } from 'vuex'
import ElementPlus from 'element-plus' // import ElementPlus from 'element-plus'
import element from './loader/el-loader'
import 'element-plus/dist/index.css' import 'element-plus/dist/index.css'
import 'element-plus/theme-chalk/dark/css-vars.css' import 'element-plus/theme-chalk/dark/css-vars.css'
import 'boxicons' import 'boxicons'
import router from './router.js' import router from './router.js'
import axios from './js/request.js'
const app = createApp(App); const app = createApp(App);
const store = createStore({ const store = createStore({
@ -13,6 +15,7 @@ const store = createStore({
} }
}); });
app.use(store); app.use(store);
app.use(ElementPlus); app.use(element);
app.use(router); app.use(router);
app.config.globalProperties.$axios = axios;
app.mount('#app'); app.mount('#app');

View File

@ -23,6 +23,29 @@ wordIn 的前端代码已经开源 [Git Repository](https://git.zjueva.net/cast1
## 3.更新日志 ## 3.更新日志
### 1.0.2 Beta 2
1. 更新内容
- 减小了打包体积
2. Bug修复进度
- (解决中)自定义背景
- 已解决移动端UI错位问题
### 1.0.2 Beta 1
1. 更新内容
- 重写对话框组件
- 增加了一些单词本管理功能
2. Bug修复进度
- (解决中)自定义背景
- 解决中移动端UI错位问题
### 1.0.1 Release ### 1.0.1 Release
#### 1.0.1 是wordIn第一个正式版 #### 1.0.1 是wordIn第一个正式版
@ -42,6 +65,16 @@ wordIn 的前端代码已经开源 [Git Repository](https://git.zjueva.net/cast1
- (已修复)查看之前的单词时溢出的错误 - (已修复)查看之前的单词时溢出的错误
- (解决中)手机端适配问题 - (解决中)手机端适配问题
#### Patch 1
- 增加了移动端底部导航栏
- 修复了无法随机顺序问题
#### Patch 2
- 封装网络请求
- 其他源码优化
### 1.0 ### 1.0
#### 1.0 及之前的版本汇总 #### 1.0 及之前的版本汇总

View File

@ -3,8 +3,9 @@ const path = require('path');
module.exports = defineConfig({ module.exports = defineConfig({
transpileDependencies: true, transpileDependencies: true,
publicPath:"./", publicPath:"./",
outputDir:"page",
devServer: { devServer: {
proxy: 'https://localhost:443' proxy: 'https://app.cast1e.top/wordin'
}, },
chainWebpack: config => { chainWebpack: config => {
config.module config.module