wordset-managing functions

master
cast1e 2024-04-12 09:52:25 +08:00
parent 34ad23db7a
commit a4a5e7ce9b
9 changed files with 352 additions and 63 deletions

View File

@ -116,13 +116,19 @@ export default {
}
}
#app{
transition: .5s;
}
html {
--bg-color-solid:#e8e8e8;
--bg-color: #ffffffae;
--text-color: #464646;
--bd-color: #bbbbbb99;
}
html.dark {
--bg-color-solid:#191919;
--bg-color: #2a2a2a88;
--text-color: #c0c0c0;
--bd-color: #7f7f7f7c;
@ -179,6 +185,10 @@ html.bgimged .card {
.para {
margin: 15px;
}
.blured {
filter: blur(10px);
}
</style>
<style scoped>

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>
<span class="text-large font-600 mr-3"> {{ set }} : {{ book }} ({{ id }}) </span>
</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>
<div class="colbox" id="main">
<div style="flex-grow: 1;" class="card">
@ -19,6 +32,8 @@
</template>
<script>
import { ElMessage } from 'element-plus';
export default {
name: "NoteEditor",
data() {
@ -26,10 +41,17 @@ export default {
table: [],
}
},
methods:{
download(){
this.$store.state.wordsets.fromArray(this.table,this.book,this.name);
ElMessage("下载完毕");
}
},
created() {
this.set = this.$route.query.set;
this.book = this.$route.query.book;
this.id = this.$route.query.id;
this.name = this.$route.query.name || "default";
if (this.set && this.book && this.id) {
this.$axios.get("wordset/detail", {
params:{

View File

@ -1,15 +1,31 @@
<template>
<div class="container" style="overflow: auto;">
<el-page-header style="margin: 10px;" @back="this.$router.push('/manage');">
<template #content>
<span class="text-large font-600 mr-3"> {{ name }} ({{ id }}) </span>
</template>
<template #content>
<span class="text-large font-600 mr-3"> {{ name }} ({{ id }}) </span>
</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>
<div class="colbox" id="main">
<div class="rowbox">
<div class="card">
<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">
<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>
@ -17,7 +33,8 @@
<div class="colbox">
<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-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>
</div>
<el-button @click="add_word()" type="primary">添加</el-button>
@ -51,28 +68,54 @@
</div>
</div>
</div>
<el-dialog v-model="word_editing" width="80%">
<div class="title">修改单词</div>
<el-input v-model="editing_word.word"></el-input>
<div class="colbox">
<el-text class="mx-1" style="width: 60px;">翻译:</el-text>
<el-input v-model="editing_word.trans"></el-input>
</div>
<div class="colbox">
<el-text class="mx-1" style="width: 80px;">词性</el-text>
<el-select v-model="editing_word.type" class="m-2" placeholder="Select">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
<el-button @click="save_word" type="primary">更改</el-button>
</el-dialog>
<CDialog v-model:visible="word_editing">
<template #content>
<div class="title">修改单词</div>
<el-input v-model="editing_word.word"></el-input>
<div class="colbox">
<el-text class="mx-1" style="width: 60px;">翻译:</el-text>
<el-input v-model="editing_word.trans"></el-input>
</div>
<div class="colbox">
<el-text class="mx-1" style="width: 80px;">词性</el-text>
<el-select v-model="editing_word.type" class="m-2" placeholder="Select">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
<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>
<script>
import { ElMessage } from 'element-plus';
import { ElMessage, ElMessageBox } from 'element-plus';
import CDialog from '../UI/CDialog.vue'
export default {
name: "NoteEditor",
components: {
CDialog
},
data() {
return {
new_word: {
@ -90,8 +133,13 @@ export default {
table: [],
word_editing: false,
new_name: "",
name:"",
id:""
name: "",
id: "",
select: {
visible: false,
set_class: "",
id: ""
}
}
},
methods: {
@ -113,7 +161,7 @@ export default {
return;
}
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({
message: `已添加 ${this.new_word.word} (${this.new_word.type})`,
type: 'success',
@ -143,7 +191,7 @@ export default {
type: this.editing_word.type,
trans: this.editing_word.trans,
}
this.$store.state.wordsets.saveSet(this.id,this.table);
this.$store.state.wordsets.saveSet(this.id, this.table);
ElMessage({
message: `已保存更改`,
type: 'success',
@ -153,7 +201,7 @@ export default {
change_name() {
let old_name = this.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({
message: `已更改 ${old_name}${this.name}`,
type: 'success',
@ -163,20 +211,42 @@ export default {
del_word(index) {
let word = this.table[index].word.concat();
this.table.splice(index, 1);
this.$store.state.wordsets.saveSet(this.id,this.table);
this.$store.state.wordsets.saveSet(this.id, this.table);
ElMessage({
message: `已删除 ${word}`,
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() {
this.class_name = this.$route.query.classname;
this.id = this.$route.query.id;
if(this.id){
let status = this.$store.state.wordsets.getSetStatus(this.class_name,this.id);
if(status){
if (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);
@ -187,31 +257,31 @@ export default {
<style scoped>
@media screen and (max-width: 500px) {
#main{
#main {
flex-direction: column;
overflow: scroll;
}
.title{
.title {
font-size: 25px;
min-height: 50px;
}
}
@media screen and (min-width: 500px) {
.title{
.title {
font-size: 35px;
min-height: 60px;
}
.container{
.container {
padding: 10px;
height: calc(100% - 70px);
padding-top: 0;
}
}
}
#main{
#main {
height: calc(100% - 50px);
}

View File

@ -6,15 +6,24 @@
<span class="text-large font-600 mr-3"> 编辑单词本 </span>
</template>
<template #extra>
<div class="pconly">
<el-button @click="manage_online_wordsets" type="primary"><box-icon color="white" name='world'
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"
<div>
<el-button @click="$router.push('/manage/new')" type="success"><box-icon color="white"
name='plus'></box-icon></el-button>
<el-dropdown trigger="click" class="pconly" 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>
</template>
</el-page-header>
@ -45,7 +54,8 @@
<el-main id="wordsets-container">
<div id="sets-container">
<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">
{{ index + 1 }}
</div>
@ -73,7 +83,8 @@
创建日期{{ (new Date(wordset.created)).toLocaleString() }}
</div>
<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>
@ -127,20 +138,20 @@ export default {
del(class_name, id, index) {
ElMessageBox.confirm("确定要删除吗?")
.then(() => {
this.$store.state.wordsets.delSet(class_name,index);
this.$store.state.wordsets.delSet(class_name, index);
ElMessage(`已经删除 ${class_name} ${id}`);
});
},
edit(id) {
this.$router.push({
path: "./manage/edit",
query: { id,classname:this.view_wordsets}
query: { id, classname: this.view_wordsets }
})
},
show(id) {
show(id,name) {
this.$router.push({
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() {
@ -165,15 +176,15 @@ export default {
let node = document.getElementById("sidebar");
if (node.style.width === "180px") {
node.style.width = "0";
setTimeout(()=>{
setTimeout(() => {
node.style.display = "none";
},500)
}, 500)
}
else {
node.style.display = "block";
setTimeout(()=>{
setTimeout(() => {
node.style.width = "180px";
},0)
}, 0)
}
return;
}
@ -311,7 +322,7 @@ export default {
padding: 20px;
height: 220px;
width: 170px;
margin: 20px;
margin: 20px;
}
.no {
@ -340,14 +351,14 @@ export default {
}
}
.wordset{
.wordset {
background-color: var(--bg-color);
color: var(--text-color);
transition: .5s;
border: solid 1px var(--bd-color);
}
.wordset:hover{
.wordset:hover {
box-shadow: var(--el-box-shadow);
}

View File

@ -41,6 +41,14 @@ export default class _wordset {
}
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) {
let sets = JSON.parse(localStorage.getItem(id));
if (sets) {
@ -76,7 +84,7 @@ export default class _wordset {
});
localStorage.setItem(id, JSON.stringify([]));
this.save();
return;
return id;
}
saveSet(id,data){
localStorage.setItem(id, JSON.stringify(data));
@ -93,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){
let [fileHandle] = await window.showOpenFilePicker({
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,7 +1,8 @@
import {createApp} from 'vue'
import App from './App.vue'
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/theme-chalk/dark/css-vars.css'
import 'boxicons'
@ -14,7 +15,7 @@ const store = createStore({
}
});
app.use(store);
app.use(ElementPlus);
app.use(element);
app.use(router);
app.config.globalProperties.$axios = axios;
app.mount('#app');

View File

@ -4,7 +4,7 @@ module.exports = defineConfig({
transpileDependencies: true,
publicPath:"./",
devServer: {
proxy: 'https://localhost:443'
proxy: 'https://app.cast1e.top/wordin'
},
chainWebpack: config => {
config.module