update ui

This commit is contained in:
zyronon
2023-11-08 02:08:58 +08:00
parent 5e874cc04b
commit 99cc02bc3d
6 changed files with 348 additions and 42 deletions

2
components.d.ts vendored
View File

@@ -67,6 +67,6 @@ declare module 'vue' {
VolumeIcon: typeof import('./src/components/icon/VolumeIcon.vue')['default']
VolumeSetting: typeof import('./src/components/Toolbar/VolumeSetting.vue')['default']
WordList: typeof import('./src/components/WordList.vue')['default']
WordListModal: typeof import('./src/components/WordListModal.vue')['default']
WordListModal: typeof import('./src/components/Modal/WordListModal.vue')['default']
}
}

View File

@@ -271,4 +271,12 @@ footer {
color: transparent !important;
text-shadow: #b0b0b0 0 0 8rem;
user-select: none;
}
.common-title {
font-size: 20rem;
color: var(--color-font-1);
text-align: center;
margin-bottom: 10rem;
}

View File

@@ -7,7 +7,7 @@ import {Icon} from "@iconify/vue";
defineProps<{
title?: string,
icon: string,
className: string
className?: string
}>()
defineEmits(['click'])

View File

@@ -1,15 +1,29 @@
<script setup lang="ts">
import {$ref} from "vue/macros";
import WordList from "@/components/WordList.vue";
import {$computed, $ref} from "vue/macros";
import Slide from "@/components/Slide.vue";
import DictList from "@/components/DictList.vue";
import {Icon} from "@iconify/vue";
import {useBaseStore} from "@/stores/base.ts";
import {useSettingStore} from "@/stores/setting.ts";
import {useRuntimeStore} from "@/stores/runtime.ts";
import {useDisableEventListener} from "@/hooks/event.ts";
import {Dict, DictType, Sort} from "@/types.ts";
import {Dict, DictType, languageCategoryOptions, Sort} from "@/types.ts";
import {onMounted, reactive, watch} from "vue";
import {FormInstance, FormRules} from "element-plus";
import {dictionaryResources} from "@/assets/dictionary.ts";
import {cloneDeep} from "lodash-es";
import {emitter, EventKey} from "@/utils/eventBus.ts";
import ChapterList from "@/components/ChapterList.vue";
import Empty from "@/components/Empty.vue";
import BaseIcon from "@/components/BaseIcon.vue";
let data = $ref({
words: [],
index: 0
})
const store = useBaseStore()
const settingStore = useSettingStore()
@@ -19,8 +33,21 @@ const emit = defineEmits([
'close',
])
let step = $ref(0)
let isEdit = $ref(true)
useDisableEventListener()
let list = $computed(() => {
return store.myDicts.filter(v => v.type === DictType.customArticle)
.concat([
store.simple,
store.wrong,
store.collect
])
.concat([{name: '',} as any])
})
let form = reactive({
id: '',
name: '123',
@@ -33,35 +60,93 @@ let form = reactive({
let wordForm = reactive({
name: '',
translate: '',
trans: '',
usphone: '',
ukphone: '',
})
let languageCategoryList = []
let categoryList = {}
let tagList = {}
const ruleFormRef = $ref<FormInstance>()
const rules = reactive<FormRules>({
name: [
{required: true, message: '请输入名称', trigger: 'blur'},
{max: 20, message: '名称不能超过20个字符', trigger: 'blur'},
],
category: [{required: true, message: '请选择', trigger: 'change'}],
tags: [{required: true, message: '请选择', trigger: 'change'}],
languageCategory: [{required: true, message: '请选择', trigger: 'change'}],
})
const rules2 = reactive<FormRules>({
name: [
{required: true, message: '请输入单词', trigger: 'blur'},
{max: 30, message: '名称不能超过30个字符', trigger: 'blur'},
],
})
watch(() => form.languageCategory, () => form.category = '')
watch(() => form.category, () => form.tags = [])
onMounted(() => {
dictionaryResources.map(v => {
// if (!languageCategoryList.find(w => w === v.languageCategory)) {
// languageCategoryList.push(v.languageCategory)
// }
if (categoryList[v.language]) {
if (!categoryList[v.language].find(w => w === v.category)) {
categoryList[v.language].push(v.category)
}
} else {
categoryList[v.language] = [v.category]
}
if (tagList[v.category]) {
tagList[v.category] = Array.from(new Set(tagList[v.category].concat(v.tags)))
} else {
tagList[v.category] = v.tags
}
})
console.log('languageCategoryList', languageCategoryList)
console.log('categoryList', categoryList)
console.log('tagList', tagList)
})
function selectDict(dict: Dict) {
runtimeStore.editDict = cloneDeep(dict)
isEdit = false
step = 1
}
async function onSubmit() {
await ruleFormRef.validate((valid, fields) => {
if (valid) {
let data = {
sort: Sort.normal,
type: DictType.customArticle,
originWords: [],
words: [],
chapterWordNumber: 30,
chapterWords: [],
chapterIndex: 0,
chapterWordIndex: 0,
statistics: [],
articles: [],
url: '',
...form,
}
if (form.id) {
let rIndex = store.myDicts.findIndex(v => v.id === form.id)
runtimeStore.editDict = data
store.myDicts[rIndex] = cloneDeep(data)
isEdit = false
} else {
if (store.myDicts.find(v => v.name === form.name)) {
return ElMessage.warning('已有相同名称词典!')
} else {
runtimeStore.editDict = data
store.myDicts.push(cloneDeep(data))
isEdit = false
console.log('submit!', data)
}
}
@@ -74,30 +159,148 @@ async function onSubmit() {
function close() {
emit('close')
}
let isAddWord = $ref(false)
</script>
<template>
<div id="AddWordDialog">
<el-form
class="form"
ref="ruleFormRef"
:rules="rules"
:model="wordForm"
label-width="60px">
<el-form-item label="单词" prop="name">
<el-input v-model="wordForm.name"/>
</el-form-item>
<el-form-item label="翻译">
<el-input v-model="wordForm.translate" type="textarea"/>
</el-form-item>
<el-form-item label="音标">
<el-input v-model="wordForm.ukphone"/>
</el-form-item>
<div class="flex-center">
<el-button @click="step = 0">返回</el-button>
<el-button type="primary" @click="onSubmit">确定</el-button>
<div id="AddWordDialog" :class="isAddWord && 'add-word-mode'">
<Slide slide-count="2" :step="step">
<div class="page dict-list-page">
<header>
<div class="title">
我的词典
</div>
<Icon @click="close"
class="hvr-grow pointer"
width="20" color="#929596"
icon="ion:close-outline"/>
</header>
<div class="list">
<DictList
@add="step = 1;isEdit = true"
@selectDict="selectDict"
:list="list"/>
</div>
</div>
</el-form>
<div class="page add-page">
<header>
<div class="left" @click.stop="step = 0">
<Icon icon="octicon:arrow-left-24" class="go" width="20"/>
<div class="title">
词典详情
</div>
</div>
<Icon @click="close"
class="hvr-grow pointer"
width="20" color="#929596"
icon="ion:close-outline"/>
</header>
<div class="detail" v-if="!isEdit">
<div class="dict">
<div class="info">
<div class="name">{{ runtimeStore.editDict.name }}</div>
<div class="desc">{{ runtimeStore.editDict.description }}</div>
<div class="more-info">
<div class="item">词汇量{{ runtimeStore.editDict.originWords.length }}</div>
<div class="item">创建日期-</div>
<div class="item">花费时间-</div>
<div class="item">累积错误-</div>
</div>
<BaseIcon
class-name="edit-icon"
icon="tabler:edit"
@click='isAddWord = false;isEdit = true'
/>
</div>
<div class="add" v-if="isAddWord">
<div class="common-title">添加单词</div>
<el-form
class="form"
ref="ruleFormRef"
:rules="rules"
:model="wordForm"
label-width="140rem">
<el-form-item label="单词" prop="name">
<el-input v-model="wordForm.name"/>
</el-form-item>
<el-form-item label="翻译">
<el-input v-model="wordForm.trans"
placeholder="多个翻译请换行"
:autosize="{ minRows: 2, maxRows: 8 }"
type="textarea"/>
</el-form-item>
<el-form-item label="音标/发音/注音①">
<el-input v-model="wordForm.usphone"/>
</el-form-item>
<el-form-item label="音标/发音/注音②">
<el-input v-model="wordForm.ukphone"/>
</el-form-item>
<div class="flex-center">
<el-button @click="isAddWord = false">关闭</el-button>
<el-button type="primary" @click="onSubmit">确定</el-button>
</div>
</el-form>
</div>
</div>
<div class="list">
<div class="list-header">
<div class="name">单词列表</div>
<div class="flex-center gap10">
<div class="name">{{ runtimeStore.editDict.words.length }}个单词</div>
<BaseIcon icon="mi:add"
@click='isAddWord = true'
/>
</div>
</div>
<WordList
v-if="runtimeStore.editDict.words.length"
class="word-list"
:is-active="true"
@change="(i:number) => data.index = i"
:list="runtimeStore.editDict.words"
:activeIndex="data.index"/>
<Empty v-else/>
</div>
</div>
<div class="edit" v-else>
<el-form
ref="ruleFormRef"
:rules="rules"
:model="form"
label-width="120px">
<el-form-item label="名称" prop="name">
<el-input v-model="form.name"/>
</el-form-item>
<el-form-item label="描述">
<el-input v-model="form.description" type="textarea"/>
</el-form-item>
<el-form-item label="分类" prop="languageCategory">
<el-select
v-model="form.languageCategory" placeholder="请选择选项">
<el-option :label="i.name" :value="i.id" v-for="i in languageCategoryOptions"/>
</el-select>
</el-form-item>
<el-form-item label="用途" prop="category">
<el-select v-model="form.category" placeholder="请选择选项">
<el-option :label="i" :value="i" v-for="i in categoryList[form.languageCategory]"/>
</el-select>
</el-form-item>
<el-form-item label="标签" prop="tags">
<el-select
multiple
v-model="form.tags" placeholder="请选择选项">
<el-option :label="i" :value="i" v-for="i in tagList[form.category]"/>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="step = 0">返回</el-button>
<el-button type="primary" @click="onSubmit">确定</el-button>
</el-form-item>
</el-form>
</div>
</div>
</Slide>
</div>
</template>
@@ -106,22 +309,124 @@ function close() {
#AddWordDialog {
position: fixed;
width: 400rem;
height: 300rem;
width: 600rem;
height: 70vh;
left: 50%;
top: 50%;
transform: translate3D(-50%, -50%, 0);
z-index: 9999999;
background: var(--color-second-bg);
transition: all .3s;
display: flex;
align-items: center;
justify-content: center;
$header-height: 60rem;
&.add-word-mode {
width: 800rem;
.form {
width: 90%;
.more-info {
display: grid;
grid-template-columns: repeat(2, 1fr);
}
}
$header-height: 60rem;
header {
color: var(--color-font-3);
display: flex;
justify-content: space-between;
align-items: center;
height: $header-height;
.left {
cursor: pointer;
display: flex;
gap: 10rem;
align-items: center;
}
}
.dict-list-page {
padding: 0 $space;
box-sizing: border-box;
}
.add-page {
color: var(--color-font-1);
//display: flex;
//flex-direction: column;
header {
padding: 0 $space;
}
.detail {
flex: 1;
height: calc(100% - $header-height);
display: flex;
position: relative;
.dict {
flex: 1;
border-radius: 10rem;
background: var(--color-second-bg);
color: var(--color-font-1);
padding-left: $space;
box-sizing: border-box;
.info {
border-radius: 8rem;
background: var(--color-item-bg);
padding: 20rem;
position: relative;
:deep(.edit-icon) {
position: absolute;
top: 10rem;
right: 10rem;
}
.name {
font-size: 24rem;
margin-bottom: 10rem;
}
.desc {
font-size: 18rem;
margin-bottom: 30rem;
}
.item {
margin-top: 10rem;
}
}
.add {
margin-top: 20rem;
}
}
.list {
width: 350rem;
display: flex;
flex-direction: column;
font-size: 14rem;
padding-bottom: 20rem;
.list-header {
min-height: 50rem;
padding: 10rem 24rem;
box-sizing: border-box;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 16rem;
color: var(--color-font-3);
.name {
font-size: 18rem;
}
}
}
}
}
}
</style>

View File

@@ -13,7 +13,7 @@ import {v4 as uuidv4} from "uuid";
import {ActivityCalendar} from "vue-activity-calendar";
import "vue-activity-calendar/style.css";
import ChapterList from "@/components/ChapterList.vue";
import WordListModal from "@/components/WordListModal.vue";
import WordListModal from "@/components/Modal/WordListModal.vue";
import {isArticle} from "@/hooks/article.ts";
import {useRuntimeStore} from "@/stores/runtime.ts";
import {useSettingStore} from "@/stores/setting.ts";
@@ -490,13 +490,6 @@ $header-height: 60rem;
position: relative;
gap: $space;
.common-title {
font-size: 20rem;
color: var(--color-font-1);
text-align: center;
margin-bottom: 10rem;
}
.detail {
overflow: auto;
flex: 3;

View File

@@ -130,7 +130,7 @@ onUnmounted(() => {
</style>
<style lang="scss">
@import "@/assets/css/variable.scss";
@import "@/assets/css/variable";
.virtual-list {
overflow: auto;