开发反馈弹窗

This commit is contained in:
zyronon
2023-08-23 16:44:49 +08:00
parent 093c84964a
commit 0291476e4c
13 changed files with 450 additions and 275 deletions

View File

@@ -22,7 +22,7 @@ import Backgorund from "@/components/Backgorund.vue"
import Statistics from "@/components/Modal/Statistics.vue";
import useThemeColor from "@/hooks/useThemeColor";
import Tooltip from "@/components/Tooltip.vue";
import Toolbar from "@/components/Toolbar.vue"
import Toolbar from "@/components/Toolbar/Toolbar.vue"
import {KeyboardOne} from "@icon-park/vue-next";
import BaseButton from "@/components/BaseButton.vue";
@@ -168,7 +168,7 @@ const {appearance, toggle} = useThemeColor()
</script>
<template>
<Backgorund/>
<!-- <Backgorund/>-->
<div class="main-page">
<div class="center">
<Toolbar/>
@@ -215,13 +215,13 @@ const {appearance, toggle} = useThemeColor()
.main-page {
position: absolute;
z-index: 1;
//background: $dark-main-bg;
width: 100vw;
height: 100%;
overflow: hidden;
font-size: 14rem;
display: flex;
justify-content: center;
background-color: var(--color-main-bg);
.center {
width: 70vw;

View File

@@ -4,7 +4,7 @@
:root {
--color-main-bg: rgb(226, 226, 226);
--color-second-bg: rgb(238,240,244);
--color-second-bg: rgb(238, 240, 244);
--color-header-bg: white;
--color-font: black;
}
@@ -27,6 +27,10 @@ html, body {
width: 100%;
height: 100%;
color: $font-color;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',
'Helvetica Neue', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
#app {
@@ -34,6 +38,12 @@ html, body {
height: 100%;
}
a {
//color: white;
text-decoration: none;
}
::-webkit-scrollbar {
width: 8rem;
height: 10rem;

View File

@@ -3,17 +3,17 @@ import {KeyboardOne} from "@icon-park/vue-next";
import Tooltip from "@/components/Tooltip.vue";
const props = defineProps<{
keyboard: string,
keyboard?: string,
active?: boolean
}>()
</script>
<template>
<Tooltip :title="`快捷键: ${keyboard}`">
<Tooltip :disabled="!keyboard" :title="`快捷键: ${keyboard}`">
<div class="my-button" :class="active && 'active'">
<span><slot></slot></span>
<div class="key-notice">
<div class="key-notice" v-if="keyboard">
<keyboard-one theme="outline" size="14" fill="#ffffff" :strokeWidth="2"/>
<span class="key">{{ keyboard }}</span>
</div>
@@ -36,12 +36,16 @@ const props = defineProps<{
//background: #999;
//background: rgb(60, 63, 65);
//background: var(--color-second-bg);
color: white;
height: 40rem;
line-height: 1;
& > span {
font-size: 16rem;
color: white;
::v-deep a {
color: white;
}
}
&:hover {

View File

@@ -2,11 +2,24 @@
import {Close} from "@icon-park/vue-next"
import {onMounted} from "vue";
const props = defineProps(['modelValue', 'title', 'subTitle'])
const emit = defineEmits(['update:modelValue'])
interface IProps {
modelValue: boolean,
title?: string,
subTitle?: string,
}
const props = withDefaults(defineProps<IProps>(), {
modelValue: true,
})
const emit = defineEmits([
'update:modelValue',
'close'
])
function close() {
emit('update:modelValue', false)
emit('close',)
}
onMounted(() => {
@@ -123,7 +136,7 @@ $header-height: 60rem;
.modal {
position: relative;
background: var(--color-main-bg);
box-shadow: var(--color-main-bg) 0 0 10rem 1rem;
//box-shadow: var(--color-main-bg) 0 0 10rem 1rem;
//width: 75vw;
//height: 70vh;
border-radius: $radius;

View File

@@ -136,13 +136,15 @@ function changeDict(dict: Dict, i: number) {
display: flex;
flex-direction: column;
transition: all .3s;
transform: rotate(-90deg);
transform-origin: 0 0;
//transform: rotate(-90deg);
//transform-origin: 0 0;
z-index: 1;
opacity: 0;
&.open {
//margin-right: 0;
transform: rotate(0deg);
//transform: rotate(0deg);
opacity: 1;
}
$header-height: 40rem;

View File

@@ -0,0 +1,87 @@
<script setup lang="ts">
import Modal from "@/components/Modal/Modal.vue"
import {HeadphoneSound, SettingConfig} from "@icon-park/vue-next"
import {useBaseStore} from "@/stores/base.ts"
import BaseButton from "@/components/BaseButton.vue";
import {GITHUB} from "@/config/ENV.ts";
interface IProps {
modelValue: boolean,
}
const props = withDefaults(defineProps<IProps>(), {
modelValue: true,
})
const emit = defineEmits([
'update:modelValue',
])
const store = useBaseStore()
</script>
<template>
<Modal
:modelValue="props.modelValue"
@close="emit('update:modelValue',false)"
title="反馈">
<div class="feedback-modal">
<div>
给我发Email<a href="mailto:zyronon@163.com">zyronon@163.com</a>
</div>
<p>or</p>
<div class="github">
<span><a :href="GITHUB" target="_blank">Github</a>上给我提一个
<a :href="`${GITHUB}/issues`" target="_blank">Issue</a>
</span>
<div class="options">
<BaseButton>
<a :href="`${GITHUB}/issues/new?assignees=&labels=&projects=&template=%E5%8D%95%E8%AF%8D%E9%94%99%E8%AF%AF---word-error.md&title=%E5%8D%95%E8%AF%8D%E9%94%99%E8%AF%AF+%7C+Word+error`"
target="_blank">字典错误</a>
</BaseButton>
<BaseButton>
<a :href="`${GITHUB}/issues/new?assignees=&labels=&projects=&template=问题报告---bug-report-.md&title=问题报告+%7C+Bug+report+`"
target="_blank">反馈BUG</a>
</BaseButton>
<BaseButton>
<a :href="`${GITHUB}/issues/new?assignees=&labels=&projects=&template=功能请求---feature-request.md&title=功能请求+%7C+Feature+request`"
target="_blank">功能请求</a>
</BaseButton>
</div>
</div>
</div>
</Modal>
</template>
<style scoped lang="scss">
@import "@/assets/css/colors.scss";
.feedback-modal {
width: 500rem;
//height: 80vh;
display: flex;
flex-direction: column;
background: white;
align-items: center;
padding: $space;
//justify-content: center;
color: var(--color-font);
p {
font-size: 30rem;
}
.github {
display: flex;
align-items: center;
gap: $space;
.options {
display: flex;
flex-direction: column;
gap: 10rem;
}
}
}
</style>

View File

@@ -1,78 +1,29 @@
<script setup lang="ts">
import Tooltip from "@/components/Tooltip.vue"
import {
MenuFold,
Moon,
PreviewCloseOne,
PreviewOpen,
SettingTwo,
SunOne,
VolumeNotice,
HeadphoneSound,
SettingConfig,
Down,
DatabaseFail
} from "@icon-park/vue-next"
import IconRepeat from '~icons/tabler/repeat'
import useThemeColor from "@/hooks/useThemeColor.ts"
import {useBaseStore} from "@/stores/base.ts"
import {reactive} from "vue"
import Modal from "@/components/Modal/Modal.vue"
import {HeadphoneSound, SettingConfig} from "@icon-park/vue-next"
import {useBaseStore} from "@/stores/base.ts"
const {appearance, toggle} = useThemeColor()
const store = useBaseStore()
const tabIndex = $ref(0)
const setting = reactive({
showToolbar: true,
show: false,
value1: false,
value2: 50,
value3: 1,
value4: false,
const store = useBaseStore()
interface IProps {
modelValue: boolean,
}
const props = withDefaults(defineProps<IProps>(), {
modelValue: true,
})
const emit = defineEmits([
'update:modelValue',
])
</script>
<template>
<header :class="!setting.showToolbar && 'hide'">
<div class="info" @click="store.dictModalIsOpen = true">
CTE-4 第5章
</div>
<div class="options">
<Tooltip title="切换主题">
<moon v-if="appearance === 'dark'" theme="filled" size="20" fill="#0C8CE9" :strokeWidth="2"
@click="toggle"/>
<sun-one v-else theme="filled" size="20" fill="#0C8CE9" :strokeWidth="2" @click="toggle"/>
</Tooltip>
<Tooltip title="设置">
<setting-two @click="setting.show = true" theme="filled" size="20" fill="#0C8CE9" :strokeWidth="2"/>
</Tooltip>
<Tooltip title="反馈字典错误">
<database-fail theme="outline" size="24" fill="#333"/>
</Tooltip>
<Tooltip title="音效设置">
<volume-notice theme="filled" size="20" fill="#0C8CE9" :strokeWidth="2"/>
</Tooltip>
<IconRepeat></IconRepeat>
<Tooltip title="单词本">
<preview-open theme="filled" size="20" fill="#0C8CE9" :strokeWidth="2"/>
<preview-close-one theme="filled" size="20" fill="#0C8CE9" :strokeWidth="2"/>
</Tooltip>
<div class="my-button" @click="store.dictModalIsOpen2 = true">ok</div>
<Tooltip title="单词本">
<menu-fold class="menu" @click="store.sideIsOpen = !store.sideIsOpen"
theme="outline" size="20" fill="#929596"
:strokeWidth="2"/>
</Tooltip>
</div>
<Tooltip :title="setting.showToolbar?'收起':'展开'">
<down
@click="setting.showToolbar = !setting.showToolbar"
class="arrow"
:class="!setting.showToolbar && 'down'"
theme="outline" size="24" fill="#999"/>
</Tooltip>
</header>
<Modal v-model="setting.show" title="设置" subTitle="修改立即生效,实时保存">
<Modal
:modelValue="props.modelValue"
@close="emit('update:modelValue',false)"
title="设置" subTitle="修改立即生效,实时保存">
<div class="setting-modal">
<div class="tabs">
<div class="tab" :class="tabIndex === 0 && 'active'" @click="tabIndex = 0">
@@ -89,7 +40,7 @@ const setting = reactive({
<div class="row">
<label class="main-title">所有音效</label>
<div class="wrapper">
<el-switch v-model="setting.value1"
<el-switch v-model="store.setting.value1"
inline-prompt
active-text="开"
inactive-text="关"
@@ -100,7 +51,7 @@ const setting = reactive({
<div class="row">
<label class="item-title">单词发音</label>
<div class="wrapper">
<el-switch v-model="setting.value1"
<el-switch v-model="store.setting.value1"
inline-prompt
active-text="开"
inactive-text="关"
@@ -110,22 +61,22 @@ const setting = reactive({
<div class="row">
<label class="sub-title">音量</label>
<div class="wrapper">
<el-slider v-model="setting.value2"/>
<span>{{ setting.value2 }}%</span>
<el-slider v-model="store.setting.value2"/>
<span>{{ store.setting.value2 }}%</span>
</div>
</div>
<div class="row">
<label class="sub-title">音量</label>
<div class="wrapper">
<el-slider v-model="setting.value3" :step="0.1" :max="4"/>
<span>{{ setting.value3 }}</span>
<el-slider v-model="store.setting.value3" :step="0.1" :max="4"/>
<span>{{ store.setting.value3 }}</span>
</div>
</div>
<div class="line"></div>
<div class="row">
<label class="item-title">按键音</label>
<div class="wrapper">
<el-switch v-model="setting.value1"
<el-switch v-model="store.setting.value1"
inline-prompt
active-text="开"
inactive-text="关"
@@ -135,15 +86,15 @@ const setting = reactive({
<div class="row">
<label class="sub-title">音量</label>
<div class="wrapper">
<el-slider v-model="setting.value2"/>
<span>{{ setting.value2 }}%</span>
<el-slider v-model="store.setting.value2"/>
<span>{{ store.setting.value2 }}%</span>
</div>
</div>
<div class="line"></div>
<div class="row">
<label class="item-title">释义发音</label>
<div class="wrapper">
<el-switch v-model="setting.value1"
<el-switch v-model="store.setting.value1"
inline-prompt
active-text="开"
inactive-text="关"
@@ -153,15 +104,15 @@ const setting = reactive({
<div class="row">
<label class="sub-title">音量</label>
<div class="wrapper">
<el-slider v-model="setting.value2"/>
<span>{{ setting.value2 }}%</span>
<el-slider v-model="store.setting.value2"/>
<span>{{ store.setting.value2 }}%</span>
</div>
</div>
<div class="line"></div>
<div class="row">
<label class="item-title">效果音章节结算页烟花音效</label>
<div class="wrapper">
<el-switch v-model="setting.value1"
<el-switch v-model="store.setting.value1"
inline-prompt
active-text="开"
inactive-text="关"
@@ -171,8 +122,8 @@ const setting = reactive({
<div class="row">
<label class="sub-title">音量</label>
<div class="wrapper">
<el-slider v-model="setting.value2"/>
<span>{{ setting.value2 }}%</span>
<el-slider v-model="store.setting.value2"/>
<span>{{ store.setting.value2 }}%</span>
</div>
</div>
</div>
@@ -180,7 +131,7 @@ const setting = reactive({
<div class="row">
<label class="item-title">章节乱序</label>
<div class="wrapper">
<el-switch v-model="setting.value1"
<el-switch v-model="store.setting.value1"
inline-prompt
active-text="开"
inactive-text="关"
@@ -194,7 +145,7 @@ const setting = reactive({
<div class="row">
<label class="item-title">练习时展示上一个/下一个单词</label>
<div class="wrapper">
<el-switch v-model="setting.value1"
<el-switch v-model="store.setting.value1"
inline-prompt
active-text="开"
inactive-text="关"
@@ -208,7 +159,7 @@ const setting = reactive({
<div class="row">
<label class="item-title">是否忽略大小写</label>
<div class="wrapper">
<el-switch v-model="setting.value1"
<el-switch v-model="store.setting.value1"
inline-prompt
active-text="开"
inactive-text="关"
@@ -222,7 +173,7 @@ const setting = reactive({
<div class="row">
<label class="item-title">是否允许默写模式下显示提示</label>
<div class="wrapper">
<el-switch v-model="setting.value1"
<el-switch v-model="store.setting.value1"
inline-prompt
active-text="开"
inactive-text="关"
@@ -239,15 +190,15 @@ const setting = reactive({
<div class="row">
<label class="sut-title">外语字体</label>
<div class="wrapper">
<el-slider v-model="setting.value2"/>
<span>{{ setting.value2 }}px</span>
<el-slider v-model="store.setting.value2"/>
<span>{{ store.setting.value2 }}px</span>
</div>
</div>
<div class="row">
<label class="sut-title">中文字体</label>
<div class="wrapper">
<el-slider v-model="setting.value2"/>
<span>{{ setting.value2 }}px</span>
<el-slider v-model="store.setting.value2"/>
<span>{{ store.setting.value2 }}px</span>
</div>
</div>
</div>
@@ -259,53 +210,6 @@ const setting = reactive({
<style scoped lang="scss">
@import "@/assets/css/colors.scss";
header {
margin-top: 10rem;
height: 60rem;
width: 50%;
background: var(--color-header-bg);
display: flex;
justify-content: space-between;
border-radius: 8rem;
position: relative;
z-index: 2;
padding: 10rem $space;
box-sizing: border-box;
transition: all .3s;
.info {
font-size: 22rem;
color: black;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.options {
display: flex;
align-items: center;
gap: 10rem;
}
&.hide {
transform: translateY(calc(-100% - 10rem));
}
.arrow {
position: absolute;
bottom: 0;
left: 50%;
cursor: pointer;
transition: all .5s;
transform: translate3d(-50%, 120%, 0) rotate(180deg);
&.down {
transform: translate3d(-50%, 120%, 0) rotate(0);
}
}
}
.setting-modal {
width: 40vw;
height: 80vh;
@@ -388,5 +292,4 @@ header {
}
}
</style>

View File

@@ -0,0 +1,120 @@
<script setup lang="ts">
import Tooltip from "@/components/Tooltip.vue"
import {
DatabaseFail,
Down,
MenuFold,
Moon,
PreviewCloseOne,
PreviewOpen,
SettingTwo,
SunOne,
VolumeNotice,
Bug
} from "@icon-park/vue-next"
import IconRepeat from '~icons/tabler/repeat'
import useThemeColor from "@/hooks/useThemeColor.ts"
import {useBaseStore} from "@/stores/base.ts"
import SettingModal from "@/components/Toolbar/SettingModal.vue"
import FeedbackModal from "@/components/Toolbar/FeedbackModal.vue"
const {appearance, toggle} = useThemeColor()
const store = useBaseStore()
const showFeedbackModal = $ref(false)
const showSettingModal = $ref(false)
</script>
<template>
<header :class="!store.setting.showToolbar && 'hide'">
<div class="info" @click="store.dictModalIsOpen = true">
CTE-4 第5章
</div>
<div class="options">
<Tooltip title="切换主题">
<moon v-if="appearance === 'dark'" theme="filled" size="20" fill="#0C8CE9" :strokeWidth="2"
@click="toggle"/>
<sun-one v-else theme="filled" size="20" fill="#0C8CE9" :strokeWidth="2" @click="toggle"/>
</Tooltip>
<Tooltip title="设置">
<setting-two @click="showSettingModal = true" theme="filled" size="20" fill="#0C8CE9" :strokeWidth="2"/>
</Tooltip>
<Tooltip title="反馈">
<bug @click="showFeedbackModal = true" theme="outline" size="20" fill="#999" :strokeWidth="2"/>
</Tooltip>
<Tooltip title="音效设置">
<volume-notice theme="filled" size="20" fill="#0C8CE9" :strokeWidth="2"/>
</Tooltip>
<IconRepeat></IconRepeat>
<Tooltip title="单词本">
<preview-open theme="filled" size="20" fill="#0C8CE9" :strokeWidth="2"/>
<preview-close-one theme="filled" size="20" fill="#0C8CE9" :strokeWidth="2"/>
</Tooltip>
<div class="my-button" @click="store.dictModalIsOpen2 = true">ok</div>
<Tooltip title="单词本">
<menu-fold class="menu" @click="store.sideIsOpen = !store.sideIsOpen"
theme="outline" size="20" fill="#929596"
:strokeWidth="2"/>
</Tooltip>
</div>
<Tooltip :title="store.setting.showToolbar?'收起':'展开'">
<down
@click="store.setting.showToolbar = !store.setting.showToolbar"
class="arrow"
:class="!store.setting.showToolbar && 'down'"
theme="outline" size="24" fill="#999"/>
</Tooltip>
</header>
<SettingModal v-model="showSettingModal"/>
<FeedbackModal v-model="showFeedbackModal"/>
</template>
<style scoped lang="scss">
@import "@/assets/css/colors.scss";
header {
margin-top: 10rem;
height: 60rem;
width: 50%;
background: var(--color-header-bg);
display: flex;
justify-content: space-between;
border-radius: 8rem;
position: relative;
z-index: 2;
padding: 10rem $space;
box-sizing: border-box;
transition: all .3s;
.info {
font-size: 22rem;
color: black;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.options {
display: flex;
align-items: center;
gap: 10rem;
}
&.hide {
transform: translateY(calc(-100% - 10rem));
}
.arrow {
position: absolute;
bottom: 0;
left: 50%;
cursor: pointer;
transition: all .5s;
transform: translate3d(-50%, 120%, 0) rotate(180deg);
&.down {
transform: translate3d(-50%, 120%, 0) rotate(0);
}
}
}
</style>

View File

@@ -10,6 +10,12 @@ export default {
return ''
}
},
disabled: {
type: Boolean,
default() {
return false
}
}
},
data() {
return {
@@ -18,6 +24,7 @@ export default {
},
methods: {
showPop(e) {
if (this.disabled) return
e.stopPropagation()
let rect = e.target.getBoundingClientRect()
this.show = true

1
src/config/ENV.ts Normal file
View File

@@ -0,0 +1 @@
export const GITHUB = 'https://github.com/zyronon/bbword'

12
src/hooks/useEsc.ts Normal file
View File

@@ -0,0 +1,12 @@
import {onMounted} from "vue"
export function useEsc(can: boolean) {
onMounted(() => {
window.addEventListener('keyup', (e: KeyboardEvent) => {
if (e.key === 'Escape' && can) {
close()
}
})
})
return [useEsc()]
}

View File

@@ -3,130 +3,138 @@ import {Config, Dict, DictType, SaveKey, State, Word} from "../types.ts"
import {chunk, cloneDeep} from "lodash";
export const useBaseStore = defineStore('base', {
state: (): State => {
return {
newWordDict: {
type: DictType.newWordDict,
wordList: [],
chapterList: [],
chapterIndex: -1,
wordIndex: -1,
},
skipWordDict: {
type: DictType.skipWordDict,
wordList: [],
chapterList: [],
chapterIndex: -1,
wordIndex: -1,
},
dict: {
type: DictType.inner,
name: '新概念英语-2',
description: '新概念英语第二册',
category: '青少年英语',
tags: ['新概念英语'],
url: '/dicts/NCE_2.json',
length: 858,
language: 'en',
languageCategory: 'en',
wordList: [],
chapterList: [],
chapterIndex: 0,
wordIndex: 0,
},
currentDictType: {
name: DictType.inner,
dictUrl: '/dicts/NCE_2.json'
},
sideIsOpen: false,
dictModalIsOpen: false,
dictModalIsOpen2: false,
}
},
getters: {
skipWordNames: (state: State) => {
return state.skipWordDict.wordList.map(v => v.name)
},
currentDict(state: State): Dict {
switch (state.currentDictType.name) {
case DictType.newWordDict:
return state.newWordDict
case DictType.skipWordDict:
return state.skipWordDict
case DictType.inner:
case DictType.custom:
return state.dict
}
},
chapter(): Word[] {
return this.currentDict.chapterList[this.currentDict.chapterIndex] ?? []
},
word(): Word {
return this.chapter[this.currentDict.wordIndex] ?? {
trans: [],
name: ''
}
},
},
actions: {
setState(obj: any) {
for (const [key, value] of Object.entries(obj)) {
this[key] = value
}
console.log('this/', this)
},
async init() {
let configStr = localStorage.getItem(SaveKey)
if (configStr) {
let obj: Config = JSON.parse(configStr)
this.setState(obj)
}
if (this.currentDictType.name === DictType.inner) {
let r = await fetch(`/public/${this.currentDictType.dictUrl}`)
r.json().then(v => {
this.dict.wordList = v
this.dict.chapterList = chunk(this.dict.wordList, 15)
})
}
if (this.currentDictType.name === DictType.custom) {
let r = await fetch(`/public/${this.currentDictType.dictUrl}`)
r.json().then(v => {
this.dict.wordList = v
this.dict.chapterList = chunk(this.dict.wordList, 15)
})
}
this.dictModalIsOpen = false
this.dictModalIsOpen2 = false
},
async changeDict(dict: Dict, chapterIndex: number = -1, wordIndex: number = -1) {
console.log('changeDict')
if ([DictType.newWordDict, DictType.skipWordDict].includes(dict.type)) {
this.currentDictType.name = dict.type
this.currentDictType.dictUrl = ''
this[dict.type].chapterList = [this[dict.type].wordList]
this[dict.type].chapterIndex = chapterIndex === -1 ? 0 : chapterIndex
this[dict.type].wordIndex = wordIndex === -1 ? 0 : wordIndex
} else {
if (dict.name === this.dict.name) {
this.currentDictType.name = dict.type
this.currentDictType.dictUrl = dict.url
if (wordIndex !== -1) this.dict.wordIndex = wordIndex
if (chapterIndex !== -1) this.dict.chapterIndex = chapterIndex
} else {
// let r = await fetch(`/public/${dict.url}`)
// r.json().then(v => {
// this.currentDictType.name === dict.type
// this.currentDictType.dictUrl = dict.url
//
// })
this.dict = cloneDeep(dict)
this.dict.chapterList = chunk(this.dict.wordList, 15)
this.dict.chapterIndex = chapterIndex === -1 ? 0 : chapterIndex
this.dict.wordIndex = wordIndex === -1 ? 0 : wordIndex
state: (): State => {
return {
newWordDict: {
type: DictType.newWordDict,
wordList: [],
chapterList: [],
chapterIndex: -1,
wordIndex: -1,
},
skipWordDict: {
type: DictType.skipWordDict,
wordList: [],
chapterList: [],
chapterIndex: -1,
wordIndex: -1,
},
dict: {
type: DictType.inner,
name: '新概念英语-2',
description: '新概念英语第二册',
category: '青少年英语',
tags: ['新概念英语'],
url: '/dicts/NCE_2.json',
length: 858,
language: 'en',
languageCategory: 'en',
wordList: [],
chapterList: [],
chapterIndex: 0,
wordIndex: 0,
},
currentDictType: {
name: DictType.inner,
dictUrl: '/dicts/NCE_2.json'
},
sideIsOpen: false,
dictModalIsOpen: false,
dictModalIsOpen2: false,
setting: {
showToolbar: true,
show: false,
value1: false,
value2: 50,
value3: 1,
value4: false,
}
}
},
getters: {
skipWordNames: (state: State) => {
return state.skipWordDict.wordList.map(v => v.name)
},
currentDict(state: State): Dict {
switch (state.currentDictType.name) {
case DictType.newWordDict:
return state.newWordDict
case DictType.skipWordDict:
return state.skipWordDict
case DictType.inner:
case DictType.custom:
return state.dict
}
},
chapter(): Word[] {
return this.currentDict.chapterList[this.currentDict.chapterIndex] ?? []
},
word(): Word {
return this.chapter[this.currentDict.wordIndex] ?? {
trans: [],
name: ''
}
},
},
actions: {
setState(obj: any) {
for (const [key, value] of Object.entries(obj)) {
this[key] = value
}
console.log('this/', this)
},
async init() {
let configStr = localStorage.getItem(SaveKey)
if (configStr) {
let obj: Config = JSON.parse(configStr)
this.setState(obj)
}
if (this.currentDictType.name === DictType.inner) {
let r = await fetch(`/public/${this.currentDictType.dictUrl}`)
r.json().then(v => {
this.dict.wordList = v
this.dict.chapterList = chunk(this.dict.wordList, 15)
})
}
if (this.currentDictType.name === DictType.custom) {
let r = await fetch(`/public/${this.currentDictType.dictUrl}`)
r.json().then(v => {
this.dict.wordList = v
this.dict.chapterList = chunk(this.dict.wordList, 15)
})
}
this.dictModalIsOpen = false
this.dictModalIsOpen2 = false
},
async changeDict(dict: Dict, chapterIndex: number = -1, wordIndex: number = -1) {
console.log('changeDict')
if ([DictType.newWordDict, DictType.skipWordDict].includes(dict.type)) {
this.currentDictType.name = dict.type
this.currentDictType.dictUrl = ''
this[dict.type].chapterList = [this[dict.type].wordList]
this[dict.type].chapterIndex = chapterIndex === -1 ? 0 : chapterIndex
this[dict.type].wordIndex = wordIndex === -1 ? 0 : wordIndex
} else {
if (dict.name === this.dict.name) {
this.currentDictType.name = dict.type
this.currentDictType.dictUrl = dict.url
if (wordIndex !== -1) this.dict.wordIndex = wordIndex
if (chapterIndex !== -1) this.dict.chapterIndex = chapterIndex
} else {
// let r = await fetch(`/public/${dict.url}`)
// r.json().then(v => {
// this.currentDictType.name === dict.type
// this.currentDictType.dictUrl = dict.url
//
// })
this.dict = cloneDeep(dict)
this.dict.chapterList = chunk(this.dict.wordList, 15)
this.dict.chapterIndex = chapterIndex === -1 ? 0 : chapterIndex
this.dict.wordIndex = wordIndex === -1 ? 0 : wordIndex
}
}
}
}
},
}
},
})

View File

@@ -124,4 +124,12 @@ export interface State {
sideIsOpen: boolean,
dictModalIsOpen: boolean,
dictModalIsOpen2: boolean,
setting: {
showToolbar: boolean,
show: boolean,
value1: boolean,
value2: number,
value3: number,
value4: boolean,
}
}