add many pages
This commit is contained in:
3
components.d.ts
vendored
3
components.d.ts
vendored
@@ -11,12 +11,15 @@ declare module 'vue' {
|
||||
ArticleContentDialog: typeof import('./src/components/dialog/ArticleContentDialog.vue')['default']
|
||||
ArticleList: typeof import('./src/components/list/ArticleList.vue')['default']
|
||||
Backgorund: typeof import('./src/components/Backgorund.vue')['default']
|
||||
BackIcon: typeof import('./src/components/icon/BackIcon.vue')['default']
|
||||
BaseButton: typeof import('./src/components/BaseButton.vue')['default']
|
||||
BaseIcon: typeof import('./src/components/BaseIcon.vue')['default']
|
||||
BaseList: typeof import('./src/components/list/BaseList.vue')['default']
|
||||
ChapterName: typeof import('./src/components/toolbar/ChapterName.vue')['default']
|
||||
Close: typeof import('./src/components/icon/Close.vue')['default']
|
||||
CollectNotice: typeof import('./src/components/CollectNotice.vue')['default']
|
||||
Delete: typeof import('./src/components/icon/Delete.vue')['default']
|
||||
DeleteIcon: typeof import('./src/components/icon/DeleteIcon.vue')['default']
|
||||
Dialog: typeof import('./src/components/dialog/Dialog.vue')['default']
|
||||
DictDiglog: typeof import('./src/components/dialog/DictDiglog.vue')['default']
|
||||
DictGroup: typeof import('./src/components/list/DictGroup.vue')['default']
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"pinia": "^2.1.6",
|
||||
"sentence-splitter": "^4.2.1",
|
||||
"tesseract.js": "^4.1.1",
|
||||
"vant": "^4.8.1",
|
||||
"vue": "^3.3.4",
|
||||
"vue-activity-calendar": "^1.2.2",
|
||||
"vue-i18n": "9",
|
||||
|
||||
26
pnpm-lock.yaml
generated
26
pnpm-lock.yaml
generated
@@ -56,6 +56,9 @@ dependencies:
|
||||
tesseract.js:
|
||||
specifier: ^4.1.1
|
||||
version: 4.1.2
|
||||
vant:
|
||||
specifier: ^4.8.1
|
||||
version: 4.8.1(vue@3.3.4)
|
||||
vue:
|
||||
specifier: ^3.3.4
|
||||
version: 3.3.4
|
||||
@@ -941,6 +944,18 @@ packages:
|
||||
resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==}
|
||||
dev: false
|
||||
|
||||
/@vant/popperjs@1.3.0:
|
||||
resolution: {integrity: sha512-hB+czUG+aHtjhaEmCJDuXOep0YTZjdlRR+4MSmIFnkCQIxJaXLQdSsR90XWvAI2yvKUI7TCGqR8pQg2RtvkMHw==}
|
||||
dev: false
|
||||
|
||||
/@vant/use@1.6.0(vue@3.3.4):
|
||||
resolution: {integrity: sha512-PHHxeAASgiOpSmMjceweIrv2AxDZIkWXyaczksMoWvKV2YAYEhoizRuk/xFnKF+emUIi46TsQ+rvlm/t2BBCfA==}
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
dependencies:
|
||||
vue: 3.3.4
|
||||
dev: false
|
||||
|
||||
/@vitejs/plugin-vue-jsx@3.0.2(vite@4.4.9)(vue@3.3.4):
|
||||
resolution: {integrity: sha512-obF26P2Z4Ogy3cPp07B4VaW6rpiu0ue4OT2Y15UxT5BZZ76haUY9guOsZV3uWh/I6xc+VeiW+ZVabRE82FyzWw==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
@@ -4976,6 +4991,17 @@ packages:
|
||||
engines: {node: '>= 0.10'}
|
||||
dev: true
|
||||
|
||||
/vant@4.8.1(vue@3.3.4):
|
||||
resolution: {integrity: sha512-SkFZM3Z3Bwi5do+iQNfRgDi7b+Ka29rUUNzck06W2KoFie3CLTqSifLa5TuZCEoXPSkqR+fRH/VE5G57mmL8sg==}
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
dependencies:
|
||||
'@vant/popperjs': 1.3.0
|
||||
'@vant/use': 1.6.0(vue@3.3.4)
|
||||
'@vue/shared': 3.3.4
|
||||
vue: 3.3.4
|
||||
dev: false
|
||||
|
||||
/vinyl-fs@3.0.3:
|
||||
resolution: {integrity: sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==}
|
||||
engines: {node: '>= 0.10'}
|
||||
|
||||
34
src/App.vue
34
src/App.vue
@@ -14,7 +14,9 @@ import ArticleContentDialog from "@/components/dialog/ArticleContentDialog.vue";
|
||||
import CollectNotice from "@/components/CollectNotice.vue";
|
||||
import {SAVE_SETTING_KEY, SAVE_DICT_KEY} from "@/utils/const.ts";
|
||||
import {isMobile, shakeCommonDict} from "@/utils";
|
||||
import router from "@/router.ts";
|
||||
import router, {routes} from "@/router.ts";
|
||||
import {$ref} from "vue/macros";
|
||||
import {useRoute} from "vue-router";
|
||||
|
||||
const store = useBaseStore()
|
||||
const runtimeStore = useRuntimeStore()
|
||||
@@ -77,18 +79,44 @@ onMounted(() => {
|
||||
// router.replace('/mobile')
|
||||
}
|
||||
})
|
||||
let transitionName = $ref('go')
|
||||
const route = useRoute()
|
||||
watch(() => route.path, (to, from) => {
|
||||
// console.log('watch', to, from)
|
||||
// //footer下面的5个按钮,对跳不要用动画
|
||||
let noAnimation = [
|
||||
'/pc/practice',
|
||||
'/pc/dict',
|
||||
'/mobile',
|
||||
'/'
|
||||
]
|
||||
if (noAnimation.indexOf(from) !== -1 && noAnimation.indexOf(to) !== -1) {
|
||||
return transitionName = ''
|
||||
}
|
||||
|
||||
const toDepth = routes.findIndex(v => v.path === to)
|
||||
const fromDepth = routes.findIndex(v => v.path === from)
|
||||
transitionName = toDepth > fromDepth ? 'go' : 'back'
|
||||
// console.log('transitionName', transitionName, toDepth, fromDepth)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Backgorund/>
|
||||
<router-view/>
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition :name="transitionName">
|
||||
<keep-alive :exclude="runtimeStore.excludeRoutes">
|
||||
<component :is="Component"/>
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</router-view>
|
||||
<CollectNotice/>
|
||||
<ArticleContentDialog/>
|
||||
<SettingDialog/>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/variable";
|
||||
@import "@/assets/css/style";
|
||||
|
||||
.main-page {
|
||||
position: relative;
|
||||
|
||||
@@ -48,4 +48,30 @@
|
||||
60% {
|
||||
transform: translate3d(4px, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.go-enter-from {
|
||||
transform: translate3d(100%, 0, 0);
|
||||
}
|
||||
|
||||
//最终状态
|
||||
.back-enter-to, .back-enter-from, .go-enter-to, .go-leave-from {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
.go-leave-to {
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
}
|
||||
|
||||
.go-enter-active, .go-leave-active, .back-enter-active, .back-leave-active {
|
||||
transition: all .3s;
|
||||
}
|
||||
|
||||
|
||||
.back-enter-from {
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
}
|
||||
|
||||
.back-leave-to {
|
||||
transform: translate3d(100%, 0, 0);
|
||||
}
|
||||
|
||||
@@ -159,6 +159,20 @@ html, body {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.mobile-page {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
overflow: auto;
|
||||
font-size: 18rem;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#app {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
15
src/components/icon/BackIcon.vue
Normal file
15
src/components/icon/BackIcon.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import {Icon} from "@iconify/vue";
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Icon
|
||||
class="back-icon"
|
||||
icon="octicon:arrow-left-24" width="22"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
12
src/components/icon/DeleteIcon.vue
Normal file
12
src/components/icon/DeleteIcon.vue
Normal file
@@ -0,0 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import {Icon} from "@iconify/vue";
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Icon icon="solar:trash-bin-minimalistic-linear"/>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -44,16 +44,16 @@ const state = reactive({
|
||||
start: {x: 0, y: 0, time: 0},
|
||||
move: {x: 0, y: 0},
|
||||
wrapper: {width: 0, height: 0, childrenLength: 0},
|
||||
slideItemsWidths:[]
|
||||
slideItemsWidths: []
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.index,
|
||||
(newVal) => {
|
||||
watch(() => props.index, (newVal) => {
|
||||
if (state.localIndex !== newVal) {
|
||||
state.localIndex = newVal
|
||||
if (props.changeActiveIndexUseAnim) {
|
||||
GM.$setCss(wrapperEl.value, 'transition-duration', `300ms`)
|
||||
} else {
|
||||
GM.$setCss(wrapperEl.value, 'transition-duration', `0ms`)
|
||||
}
|
||||
GM.$setCss(wrapperEl.value, 'transform', `translate3d(${getSlideDistance(state, SlideType.HORIZONTAL)}px, 0, 0)`)
|
||||
}
|
||||
@@ -84,9 +84,9 @@ function touchEnd(e) {
|
||||
|
||||
|
||||
function canNext(isNext) {
|
||||
if (isNext){
|
||||
if (isNext) {
|
||||
return state.localIndex !== state.wrapper.childrenLength - 1
|
||||
}else {
|
||||
} else {
|
||||
return state.localIndex !== 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ export function slideInit(el, state, type) {
|
||||
if (type === SlideType.HORIZONTAL) dx1 = t
|
||||
else dx2 = t
|
||||
|
||||
console.log('start', dx1)
|
||||
// console.log('start', dx1)
|
||||
Utils.$setCss(el, 'transform', `translate3d(${dx1}px, ${dx2}px, 0)`)
|
||||
}
|
||||
|
||||
|
||||
178
src/pages/mobile/DictDetail.vue
Normal file
178
src/pages/mobile/DictDetail.vue
Normal file
@@ -0,0 +1,178 @@
|
||||
<script setup lang="ts">
|
||||
import SlideHorizontal from "@/components/slide/SlideHorizontal.vue";
|
||||
import SlideItem from "@/components/slide/SlideItem.vue";
|
||||
import {$ref} from "vue/macros";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import {showConfirmDialog, showToast} from "vant";
|
||||
import 'vant/lib/index.css'
|
||||
import {onMounted} from "vue";
|
||||
import DeleteIcon from "@/components/icon/DeleteIcon.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import {Dict} from "@/types.ts";
|
||||
import DictPlan from "@/pages/mobile/components/DictPlan.vue";
|
||||
import BackIcon from "@/components/icon/BackIcon.vue";
|
||||
import {useRouter} from "vue-router";
|
||||
|
||||
const store = useBaseStore()
|
||||
let index = $ref(0)
|
||||
const router = useRouter()
|
||||
|
||||
|
||||
const onChange = ({selectedValues}) => {
|
||||
showToast(`当前值: ${selectedValues.join(',')}`);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
})
|
||||
|
||||
function handleDel(item: Dict, index: number) {
|
||||
if (item.id === store.currentDict.id) {
|
||||
//TODO
|
||||
} else {
|
||||
showConfirmDialog({title: '确认删除?', message: '删除后无法撤销,确认删除吗?',})
|
||||
.then(() => {
|
||||
store.myDictList.splice(index, 1)
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mobile-page">
|
||||
<header>
|
||||
<BackIcon @click="router.back()"/>
|
||||
<div class="tabs">
|
||||
<div class="tab" :class="index === 0 && 'active'" @click="index = 0">修改计划</div>
|
||||
<div class="tab" :class="index === 1 && 'active'" @click="index = 1">更换词书</div>
|
||||
</div>
|
||||
</header>
|
||||
<SlideHorizontal v-model:index="index">
|
||||
<SlideItem>
|
||||
<DictPlan/>
|
||||
</SlideItem>
|
||||
<SlideItem>
|
||||
<div class="my-dcits">
|
||||
<div class="list">
|
||||
<div class="dict" v-for="(item,index) in store.myDictList">
|
||||
<div class="title">
|
||||
<div class="name">{{ item.name }}</div>
|
||||
<span v-if="item.id === store.currentDict.id">当前在学</span>
|
||||
<template v-else>
|
||||
<DeleteIcon
|
||||
v-if="index>=3"
|
||||
@click="handleDel(item,index)"/>
|
||||
</template>
|
||||
</div>
|
||||
<div class="chapter">每日{{ item.chapterWordNumber }}词 剩余100天</div>
|
||||
<el-progress
|
||||
:show-text="false"
|
||||
:percentage="90"
|
||||
/>
|
||||
<div class="progress">
|
||||
<span>已学单词</span>
|
||||
<span>0/{{ item.length }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<BaseButton size="large">添加新书</BaseButton>
|
||||
</div>
|
||||
</SlideItem>
|
||||
</SlideHorizontal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
header {
|
||||
height: 60rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
padding: 0 var(--space);
|
||||
|
||||
.back {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
width: 100%;
|
||||
border-top: 1px solid gray;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.tab {
|
||||
width: 100rem;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.active {
|
||||
border-bottom: 2px solid gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.plan {
|
||||
padding: 10rem;
|
||||
|
||||
.dict {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10rem;
|
||||
}
|
||||
|
||||
.set-plan {
|
||||
background: white;
|
||||
|
||||
.header {
|
||||
height: 60rem;
|
||||
color: black;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.picker-wrapper {
|
||||
display: flex;
|
||||
|
||||
.van-picker {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.my-dcits {
|
||||
height: 100%;
|
||||
padding: var(--space);
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.list {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
margin-bottom: 20rem;
|
||||
}
|
||||
|
||||
.dict {
|
||||
padding: var(--space);
|
||||
border-radius: var(--radius);
|
||||
background: var(--color-second-bg);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6rem;
|
||||
margin-bottom: 10rem;
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -9,8 +9,9 @@ import {dictionaryResources} from "@/assets/dictionary.ts";
|
||||
import {DictResource, languageCategoryOptions} from "@/types.ts";
|
||||
import {onMounted} from "vue";
|
||||
import DictGroup from "@/components/list/DictGroup.vue";
|
||||
import router from "@/router.ts";
|
||||
|
||||
let index = $ref(0)
|
||||
let index = $ref(1)
|
||||
|
||||
const store = useBaseStore()
|
||||
|
||||
@@ -100,6 +101,11 @@ onMounted(() => {
|
||||
let temp1 = getData('word')
|
||||
wordData = temp1
|
||||
})
|
||||
|
||||
function selectDict(val) {
|
||||
console.log('val', val)
|
||||
router.push('/mobile/set-dict-plan')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -113,7 +119,8 @@ onMounted(() => {
|
||||
<span>{{ item.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<SlideHorizontal v-model:index="index">
|
||||
<SlideHorizontal
|
||||
v-model:index="index">
|
||||
<SlideItem>
|
||||
<div class="translate">
|
||||
<span>翻译:</span>
|
||||
@@ -143,6 +150,7 @@ onMounted(() => {
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<DictGroup
|
||||
@select-dict="selectDict"
|
||||
v-for="item in wordData.dictList"
|
||||
:select-id="store.currentDict.id"
|
||||
:groupByTag="item[1]"
|
||||
@@ -8,7 +8,7 @@ import {Icon} from "@iconify/vue";
|
||||
const store = useBaseStore()
|
||||
|
||||
function goPractice() {
|
||||
router.push('/mobile-practice')
|
||||
router.push('/mobile/practice')
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -16,7 +16,7 @@ function goPractice() {
|
||||
<div class="page home">
|
||||
<div class="current-dict">
|
||||
<div class="top">
|
||||
<div class="left">
|
||||
<div class="left" @click="router.push('/mobile/dict-detail')">
|
||||
<div class="name">{{ store.currentDict.name }}</div>
|
||||
<Icon class="arrow" icon="mingcute:right-line" width="20"/>
|
||||
</div>
|
||||
|
||||
17
src/pages/mobile/SetDictPlan.vue
Normal file
17
src/pages/mobile/SetDictPlan.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import DictPlan from "@/pages/mobile/components/DictPlan.vue";
|
||||
import NavBar from "@/pages/mobile/components/NavBar.vue";
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mobile-page">
|
||||
<NavBar title="设置任务量"/>
|
||||
<DictPlan/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
118
src/pages/mobile/components/DictPlan.vue
Normal file
118
src/pages/mobile/components/DictPlan.vue
Normal file
@@ -0,0 +1,118 @@
|
||||
<script setup lang="ts">
|
||||
import {$ref} from "vue/macros";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import {Picker, showToast} from "vant";
|
||||
import 'vant/lib/index.css'
|
||||
import {onMounted} from "vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
|
||||
const store = useBaseStore()
|
||||
|
||||
let columns = $ref([])
|
||||
let columns2 = $ref([])
|
||||
|
||||
const onChange = ({selectedValues}) => {
|
||||
showToast(`当前值: ${selectedValues.join(',')}`);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
columns = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200].map(value => {
|
||||
return {
|
||||
text: value,
|
||||
value,
|
||||
}
|
||||
})
|
||||
columns2 = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200].map(value => {
|
||||
return {
|
||||
text: value,
|
||||
value,
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="plan">
|
||||
<div class="content">
|
||||
<div class="dict">
|
||||
<div class="name">{{ store.currentDict.name }}</div>
|
||||
<div class="chapter">每日{{ store.currentDict.chapterWordNumber }}词 剩余100天</div>
|
||||
<el-progress
|
||||
:show-text="false"
|
||||
:percentage="90"
|
||||
/>
|
||||
<div class="progress">
|
||||
<span>已学单词</span>
|
||||
<span>0/{{ store.currentDict.length }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="notice">
|
||||
<span>完成日期:</span>
|
||||
<span class="date">2023年1月1日</span>
|
||||
<span>预计每天11分钟</span>
|
||||
</div>
|
||||
<div class="set-plan">
|
||||
<div class="header">
|
||||
<span>每天背单词</span>
|
||||
<span>完成天数</span>
|
||||
</div>
|
||||
<div class="picker-wrapper">
|
||||
<Picker
|
||||
:show-toolbar="false"
|
||||
:columns="columns"
|
||||
@change="onChange"
|
||||
/>
|
||||
<Picker
|
||||
:show-toolbar="false"
|
||||
:columns="columns2"
|
||||
@change="onChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<BaseButton size="large">确认</BaseButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.plan {
|
||||
height: 100%;
|
||||
padding: 10rem;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
|
||||
.dict {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10rem;
|
||||
}
|
||||
|
||||
.set-plan {
|
||||
background: white;
|
||||
|
||||
.header {
|
||||
height: 60rem;
|
||||
color: black;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.picker-wrapper {
|
||||
display: flex;
|
||||
|
||||
.van-picker {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
</style>
|
||||
33
src/pages/mobile/components/NavBar.vue
Normal file
33
src/pages/mobile/components/NavBar.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import BackIcon from "@/components/icon/BackIcon.vue";
|
||||
import {useRouter} from "vue-router";
|
||||
|
||||
const router = useRouter()
|
||||
defineProps<{
|
||||
title?: string
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="nav-bar">
|
||||
<BackIcon @click="router.back()"/>
|
||||
<div class="title" v-if="title">{{ title }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.nav-bar {
|
||||
height: 60rem;
|
||||
padding: 0 var(--space);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
|
||||
:deep(.back-icon) {
|
||||
left: var(--space);
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -3,23 +3,23 @@ import {Icon} from "@iconify/vue";
|
||||
import SlideHorizontal from "@/components/slide/SlideHorizontal.vue";
|
||||
import SlideItem from "@/components/slide/SlideItem.vue";
|
||||
import Home from "@/pages/mobile/Home.vue";
|
||||
import DictManage from "@/pages/mobile/DictManage.vue";
|
||||
import DictListManage from "@/pages/mobile/DictListManage.vue";
|
||||
import Setting from "@/pages/mobile/Setting.vue";
|
||||
|
||||
let state = $ref({
|
||||
baseIndex: 1
|
||||
})
|
||||
|
||||
let index = $ref(1)
|
||||
</script>
|
||||
<template>
|
||||
<div class="page mobile">
|
||||
<div class="mobile-page mobile">
|
||||
<div class="content">
|
||||
<SlideHorizontal
|
||||
v-model:index="state.baseIndex">
|
||||
:changeActiveIndexUseAnim="false"
|
||||
v-model:index="index">
|
||||
<SlideItem>
|
||||
<Home/>
|
||||
</SlideItem>
|
||||
<SlideItem>
|
||||
<DictManage/>
|
||||
<DictListManage/>
|
||||
</SlideItem>
|
||||
<SlideItem>
|
||||
<Setting/>
|
||||
@@ -27,15 +27,15 @@ let state = $ref({
|
||||
</SlideHorizontal>
|
||||
</div>
|
||||
<div class="tabs">
|
||||
<div class="tab" @click="state.baseIndex = 0">
|
||||
<div class="tab" @click="index = 0">
|
||||
<Icon width="30" icon="icon-park:word"/>
|
||||
<span>单词</span>
|
||||
</div>
|
||||
<div class="tab" @click="state.baseIndex = 1">
|
||||
<div class="tab" @click="index = 1">
|
||||
<Icon width="30" icon="icon-park:word"/>
|
||||
<span>词典</span>
|
||||
</div>
|
||||
<div class="tab" @click="state.baseIndex = 2">
|
||||
<div class="tab" @click="index = 2">
|
||||
<Icon width="30" icon="icon-park:word"/>
|
||||
<span>我的</span>
|
||||
</div>
|
||||
@@ -45,8 +45,6 @@ let state = $ref({
|
||||
|
||||
<style scoped lang="scss">
|
||||
.mobile {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
|
||||
@@ -134,17 +134,11 @@ onUnmounted(() => {
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div class="practice-wrapper">
|
||||
<div class="mobile-page">
|
||||
<PracticeWord ref="practiceRef"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.practice-wrapper {
|
||||
font-size: 14rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -5,15 +5,18 @@ import Dict from '@/pages/pc/dict/index.vue'
|
||||
import Mobile from '@/pages/mobile/index.vue'
|
||||
import MobilePractice from '@/pages/mobile/practice/index.vue'
|
||||
import Test from "@/pages/test/test.vue";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import DictDetail from "@/pages/mobile/DictDetail.vue";
|
||||
import SetDictPlan from "@/pages/mobile/SetDictPlan.vue";
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
export const routes: RouteRecordRaw[] = [
|
||||
{path: '/pc/practice', component: Practice},
|
||||
{path: '/pc/dict', component: Dict},
|
||||
{
|
||||
path: '/mobile', component: Mobile,
|
||||
// redirect:'/mobile/home',
|
||||
},
|
||||
{path: '/mobile-practice', component: MobilePractice,},
|
||||
|
||||
{path: '/mobile', component: Mobile,},
|
||||
{path: '/mobile/practice', component: MobilePractice},
|
||||
{path: '/mobile/dict-detail', component: DictDetail},
|
||||
{path: '/mobile/set-dict-plan', component: SetDictPlan},
|
||||
{path: '/test', component: Test},
|
||||
{path: '/', redirect: '/pc/practice'},
|
||||
]
|
||||
@@ -21,6 +24,57 @@ const routes: RouteRecordRaw[] = [
|
||||
const router = VueRouter.createRouter({
|
||||
history: VueRouter.createWebHashHistory(),
|
||||
routes,
|
||||
scrollBehavior(to, from, savedPosition) {
|
||||
// console.log('savedPosition', savedPosition)
|
||||
if (savedPosition) {
|
||||
return savedPosition
|
||||
} else {
|
||||
return {top: 0}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
router.beforeEach((to, from) => {
|
||||
// console.log('beforeEach-to',to.path)
|
||||
// console.log('beforeEach-from',from.path)
|
||||
const runtimeStore = useRuntimeStore()
|
||||
|
||||
//footer下面的5个按钮,对跳不要用动画
|
||||
let noAnimation = [
|
||||
'/pc/practice',
|
||||
'/pc/dict',
|
||||
'/mobile',
|
||||
'/'
|
||||
]
|
||||
if (noAnimation.indexOf(from.path) !== -1 && noAnimation.indexOf(to.path) !== -1) {
|
||||
return true
|
||||
}
|
||||
|
||||
const toDepth = routes.findIndex(v => v.path === to.path)
|
||||
const fromDepth = routes.findIndex(v => v.path === from.path)
|
||||
// const fromDepth = routeDeep.indexOf(from.path)
|
||||
|
||||
if (toDepth > fromDepth) {
|
||||
if (to.matched && to.matched.length) {
|
||||
let toComponentName = to.matched[0].components.default.name
|
||||
runtimeStore.updateExcludeRoutes({type: 'remove', value: toComponentName})
|
||||
// console.log('to', toComponentName)
|
||||
// console.log('前进')
|
||||
// console.log('删除', toComponentName)
|
||||
}
|
||||
|
||||
} else {
|
||||
if (from.matched && from.matched.length) {
|
||||
let fromComponentName = from.matched[0].components.default.name
|
||||
runtimeStore.updateExcludeRoutes({type: 'add', value: fromComponentName})
|
||||
// console.log('后退')
|
||||
// console.log('添加', fromComponentName)
|
||||
}
|
||||
}
|
||||
// ...
|
||||
// 返回 false 以取消导航
|
||||
return true
|
||||
})
|
||||
|
||||
|
||||
export default router
|
||||
@@ -135,7 +135,7 @@ export const useBaseStore = defineStore('base', {
|
||||
].includes(this.currentDict.type)
|
||||
},
|
||||
currentDict(): Dict {
|
||||
return this.myDictList[this.current.index]
|
||||
return this.myDictList[this.current.index]??{}
|
||||
},
|
||||
chapter(state: BaseState): Word[] {
|
||||
return this.currentDict.chapterWords[this.currentDict.chapterIndex] ?? []
|
||||
|
||||
@@ -8,6 +8,7 @@ export interface RuntimeState {
|
||||
editDict: Dict
|
||||
showDictModal: boolean
|
||||
showSettingModal: boolean
|
||||
excludeRoutes: any[]
|
||||
}
|
||||
|
||||
export const useRuntimeStore = defineStore('runtime', {
|
||||
@@ -18,6 +19,22 @@ export const useRuntimeStore = defineStore('runtime', {
|
||||
editDict: cloneDeep(DefaultDict),
|
||||
showDictModal: false,
|
||||
showSettingModal: false,
|
||||
excludeRoutes: [],
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
updateExcludeRoutes(val: any) {
|
||||
if (val.type === 'add') {
|
||||
if (!this.excludeRoutes.find(v => v === val.value)) {
|
||||
this.excludeRoutes.push(val.value)
|
||||
}
|
||||
} else {
|
||||
let resIndex = this.excludeRoutes.findIndex(v => v === val.value)
|
||||
if (resIndex !== -1) {
|
||||
this.excludeRoutes.splice(resIndex, 1)
|
||||
}
|
||||
}
|
||||
// console.log('store.excludeRoutes', this.excludeRoutes)
|
||||
},
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user