fix:modify the page routing method

This commit is contained in:
zyronon
2025-08-19 23:05:51 +08:00
parent ac05cc92f0
commit f78624799d
10 changed files with 160 additions and 107 deletions

View File

@@ -25,17 +25,16 @@
"file-saver": "^2.0.5",
"idb-keyval": "^6.2.2",
"libarchive-wasm": "^1.2.0",
"md5": "^2.2.1",
"mitt": "^3.0.1",
"nanoid": "^5.1.5",
"pinia": "^3.0.3",
"string-comparison": "^1.3.0",
"vue": "^3.5.17",
"vue-router": "^4.5.1",
"vue-virtual-scroller": "2.0.0-beta.8",
"md5": "^2.2.1"
"vue-virtual-scroller": "2.0.0-beta.8"
},
"devDependencies": {
"@types/md5": "^2.1.33",
"@alicloud/pop-core": "^1.8.0",
"@iconify-json/basil": "^1.2.4",
"@iconify-json/bi": "^1.2.6",
@@ -67,6 +66,7 @@
"@iconify-json/uil": "^1.2.3",
"@types/file-saver": "^2.0.7",
"@types/lodash-es": "^4.17.12",
"@types/md5": "^2.1.33",
"@unocss/postcss": "^66.4.0",
"@vitejs/plugin-vue": "^6.0.0",
"@vitejs/plugin-vue-jsx": "^5.0.1",
@@ -86,10 +86,11 @@
"unplugin-icons": "^22.2.0",
"unplugin-vue-components": "^29.0.0",
"unplugin-vue-macros": "^2.14.5",
"vite-plugin-externals": "^0.6.2",
"vite": "^7.0.3",
"vite-plugin-externals": "^0.6.2",
"vue-tsc": "^3.0.1",
"xlsx": "^0.18.5"
"xlsx": "^0.18.5",
"sitemap": "^8.0.0"
},
"config": {
"commitizen": {

36
pnpm-lock.yaml generated
View File

@@ -44,6 +44,9 @@ importers:
pinia:
specifier: ^3.0.3
version: 3.0.3(typescript@5.9.2)(vue@3.5.18(typescript@5.9.2))
sitemap:
specifier: ^8.0.0
version: 8.0.0
string-comparison:
specifier: ^1.3.0
version: 1.3.0
@@ -953,12 +956,18 @@ packages:
'@types/md5@2.3.5':
resolution: {integrity: sha512-/i42wjYNgE6wf0j2bcTX6kuowmdL/6PE4IVitMpm2eYKBUuYCprdcWVK+xEF0gcV6ufMCRhtxmReGfc6hIK7Jw==}
'@types/node@17.0.45':
resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==}
'@types/node@20.19.11':
resolution: {integrity: sha512-uug3FEEGv0r+jrecvUUpbY8lLisvIjg6AAic6a2bSP5OEOLeJsDSnvhCDov7ipFFMXS3orMpzlmi0ZcuGkBbow==}
'@types/node@24.3.0':
resolution: {integrity: sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==}
'@types/sax@1.2.7':
resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==}
'@types/web-bluetooth@0.0.16':
resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==}
@@ -1404,6 +1413,9 @@ packages:
archy@1.0.0:
resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==}
arg@5.0.2:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
@@ -3293,6 +3305,11 @@ packages:
resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==}
engines: {node: '>=18'}
sitemap@8.0.0:
resolution: {integrity: sha512-+AbdxhM9kJsHtruUF39bwS/B0Fytw6Fr1o4ZAIAEqA6cke2xcoO2GleBw9Zw7nRzILVEgz7zBM5GiTJjie1G9A==}
engines: {node: '>=14.0.0', npm: '>=6.0.0'}
hasBin: true
snapdragon-node@2.1.1:
resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==}
engines: {node: '>=0.10.0'}
@@ -4595,6 +4612,8 @@ snapshots:
'@types/md5@2.3.5': {}
'@types/node@17.0.45': {}
'@types/node@20.19.11':
dependencies:
undici-types: 6.21.0
@@ -4602,7 +4621,10 @@ snapshots:
'@types/node@24.3.0':
dependencies:
undici-types: 7.10.0
optional: true
'@types/sax@1.2.7':
dependencies:
'@types/node': 24.3.0
'@types/web-bluetooth@0.0.16':
optional: true
@@ -5278,6 +5300,8 @@ snapshots:
archy@1.0.0: {}
arg@5.0.2: {}
argparse@2.0.1:
optional: true
@@ -7340,6 +7364,13 @@ snapshots:
mrmime: 2.0.1
totalist: 3.0.1
sitemap@8.0.0:
dependencies:
'@types/node': 17.0.45
'@types/sax': 1.2.7
arg: 5.0.2
sax: 1.4.1
snapdragon-node@2.1.1:
dependencies:
define-property: 1.0.0
@@ -7599,8 +7630,7 @@ snapshots:
undici-types@6.21.0: {}
undici-types@7.10.0:
optional: true
undici-types@7.10.0: {}
unescape@1.0.1:
dependencies:

View File

@@ -0,0 +1,41 @@
const {SitemapStream, streamToPromise} = require('sitemap')
const {createWriteStream} = require('fs')
const {resolve} = require('path')
// 你的网站域名
const SITE_URL = 'https://yourdomain.com'
// 静态路由(首页、练习页等)
const staticPages = [
{url: '/', changefreq: 'daily', priority: 1.0},
{url: '/word', changefreq: 'daily', priority: 0.9},
{url: '/article', changefreq: 'daily', priority: 0.9},
{url: '/setting', changefreq: 'monthly', priority: 0.3},
]
// 动态页面示例(假设你有文章或单词数据)
const dynamicPages = [
{url: '/article/vue-seo', changefreq: 'weekly', priority: 0.8},
{url: '/article/js-tips', changefreq: 'weekly', priority: 0.8},
// 如果文章很多,可以用 JSON / API 自动生成数组
]
async function generateSitemap() {
const sitemap = new SitemapStream({hostname: SITE_URL})
const writeStream = createWriteStream(resolve(__dirname, '../dist/sitemap.xml'))
sitemap.pipe(writeStream)
// 添加静态页
staticPages.forEach(page => sitemap.write(page))
// 添加动态页
dynamicPages.forEach(page => sitemap.write(page))
sitemap.end()
await streamToPromise(sitemap)
console.log('✅ sitemap.xml 已生成在 dist 目录')
}
generateSitemap()

View File

@@ -43,7 +43,7 @@ function startStudy() {
custom: base.sbook.custom,
complete: base.sbook.complete,
})
nav('/study-article', {name: store.sbook.name, id: store.sbook.id})
nav('/study-article/' + store.sbook.id)
} else {
window.umami?.track('no-book')
Toast.warning('请先选择一本书籍')
@@ -128,7 +128,7 @@ async function goBookDetail(val: DictResource) {
<div class="color-blue cursor-pointer" v-if="base.article.bookList.length > 1"
@click="isMultiple = !isMultiple; selectIds = []">{{ isMultiple ? '取消' : '管理书籍' }}
</div>
<div class="color-blue cursor-pointer" @click="nav('dict-detail', { isAdd: true })">创建个人书籍</div>
<div class="color-blue cursor-pointer" @click="nav('book-detail', { isAdd: true })">创建个人书籍</div>
</div>
</div>
<div class="flex gap-4 flex-wrap mt-4">

View File

@@ -146,7 +146,7 @@ const {
<div class="card mb-0 h-[95vh]" v-else>
<div class="flex justify-between items-center relative">
<BackIcon class="z-2" @click="isAdd ? $router.back():(isEdit = false)"/>
<BackIcon class="z-2" @click="isAdd ? $router.back:(isEdit = false)"/>
<div class="absolute text-2xl text-align-center w-full">{{ runtimeStore.editDict.id ? '修改' : '创建' }}书籍
</div>
</div>

View File

@@ -10,7 +10,7 @@ import useTheme from "@/hooks/theme.ts";
import Toast from '@/pages/pc/components/base/toast/Toast.ts'
import {_getDictDataByUrl, cloneDeep} from "@/utils";
import {usePracticeStore} from "@/stores/practice.ts";
import {useArticleOptions} from "@/hooks/dict.ts";
import {getCurrentStudyWord, useArticleOptions} from "@/hooks/dict.ts";
import {genArticleSectionData, usePlaySentenceAudio} from "@/hooks/article.ts";
import {getDefaultArticle, getDefaultDict} from "@/types/func.ts";
import TypingArticle from "@/pages/pc/article/components/TypingArticle.vue";
@@ -20,7 +20,7 @@ import ArticleList from "@/pages/pc/components/list/ArticleList.vue";
import EditSingleArticleModal from "@/pages/pc/article/components/EditSingleArticleModal.vue";
import Tooltip from "@/pages/pc/components/base/Tooltip.vue";
import ConflictNotice from "@/pages/pc/components/ConflictNotice.vue";
import {enArticle} from "@/assets/dictionary.ts";
import {dictionaryResources, enArticle} from "@/assets/dictionary.ts";
import {useRoute, useRouter} from "vue-router";
import {useRuntimeStore} from "@/stores/runtime.ts";
@@ -39,7 +39,7 @@ let articleData = $ref({
})
let showEditArticle = $ref(false)
let typingArticleRef = $ref<any>()
let loading = $ref<boolean>(true)
let loading = $ref<boolean>(false)
let editArticle = $ref<Article>(getDefaultArticle())
function write() {
@@ -87,61 +87,51 @@ function next() {
const router = useRouter()
const route = useRoute()
const runtimeStore = useRuntimeStore()
watch(() => store.load, (n) => {
if (n && loading && runtimeStore.editDict.id) {
console.log('load好了开始加载')
store.changeBook(runtimeStore.editDict)
articleData.list = cloneDeep(store.sbook.articles)
getCurrentPractice()
loading = false
}
},{immediate: true})
useStartKeyboardEventListener()
useDisableEventListener(() => loading)
function init() {
if (store.sbook?.articles?.length) {
articleData.list = cloneDeep(store.sbook.articles)
getCurrentPractice()
loading = false
} else {
let dictName = route.query.name
let dictId = route.query.id
//如果url里有词典id或name那么直接请求词典数据并加到bookList里面进行学习
//todo 这里要处理自定义词典的问题
if (dictName || dictId) {
let dictResource = getDefaultDict()
if (dictId) dictResource = enArticle.find(v => v.id === dictId) as Dict
else if (dictName) dictResource = enArticle.find(v => v.name === dictName) as Dict
if (dictResource.id) {
loading = true
_getDictDataByUrl(dictResource, DictType.article).then(r => {
if (!r.articles.length) {
router.push('/article')
return Toast.warning('没有文章可学习!')
}
runtimeStore.editDict = r
if (store.load) {
console.log('直接加载')
store.changeBook(r)
articleData.list = cloneDeep(store.sbook.articles)
getCurrentPractice()
loading = false
}
})
} else {
async function init() {
console.log('load好了开始加载')
let dict = getDefaultDict()
let dictId = route.params.id
if (dictId) {
//先在自己的词典列表里面找,如果没有再在资源列表里面找
dict = store.article.bookList.find(v => v.id === dictId)
if (!dict) dict = enArticle.find(v => v.id === dictId) as Dict
if (dict && dict.id) {
//如果是不是自定义词典,就请求数据
if (!dict.custom) dict = await _getDictDataByUrl(dict, DictType.article)
if (!dict.articles.length) {
router.push('/article')
return Toast.warning('没有文章可学习!')
}
store.changeBook(dict)
articleData.list = cloneDeep(store.sbook.articles)
getCurrentPractice()
loading = false
} else {
router.push('/article')
}
} else {
router.push('/article')
}
}
watch(() => store.load, (n) => {
if (n && loading) init()
}, {immediate: true})
onMounted(() => {
if (store.sbook?.articles?.length) {
articleData.list = cloneDeep(store.sbook.articles)
getCurrentPractice()
} else {
loading = true
}
})
useStartKeyboardEventListener()
useDisableEventListener(() => loading)
function setArticle(val: Article) {
statisticsStore.inputWordNumber = 0
statisticsStore.wrong = 0
@@ -246,8 +236,6 @@ async function onKeyDown(e: KeyboardEvent) {
useOnKeyboardEventListener(onKeyDown, onKeyUp)
onMounted(init)
useEvents([
[EventKey.write, write],
[EventKey.repeatStudy, repeat],

View File

@@ -61,54 +61,47 @@ let data = $ref<StudyData>({
wrongWords: [],
})
watch(() => store.load, (n) => {
if (n && loading && runtimeStore.editDict.id) {
console.log('load好了开始加载')
store.changeDict(runtimeStore.editDict)
studyData = getCurrentStudyWord()
loading = false
async function init() {
console.log('load好了开始加载')
let dict = getDefaultDict()
let dictId = route.params.id
if (dictId) {
//先在自己的词典列表里面找,如果没有再在资源列表里面找
dict = store.word.bookList.find(v => v.id === dictId)
if (!dict) dict = dictionaryResources.find(v => v.id === dictId) as Dict
if (dict && dict.id) {
//如果是不是自定义词典,就请求数据
if (!dict.custom) dict = await _getDictDataByUrl(dict)
if (!dict.words.length) {
router.push('/word')
return Toast.warning('没有单词可学习!')
}
store.changeDict(dict)
studyData = getCurrentStudyWord()
loading = false
} else {
router.push('/word')
}
} else {
router.push('/word')
}
}, {immediate: true})
}
useStartKeyboardEventListener()
useDisableEventListener(() => loading)
watch(() => store.load, (n) => {
if (n && loading) init()
}, {immediate: true})
onMounted(() => {
if (runtimeStore.routeData) {
studyData = runtimeStore.routeData
} else {
let dictName = route.query.name
let dictId = route.query.id
//如果url里有词典id或name那么直接请求词典数据并加到bookList里面进行学习
//todo 这里要处理自定义词典的问题
if (dictName || dictId) {
let dictResource = getDefaultDict()
if (dictId) dictResource = dictionaryResources.find(v => v.id === dictId) as Dict
else if (dictName) dictResource = dictionaryResources.find(v => v.name === dictName) as Dict
if (dictResource.id) {
loading = true
_getDictDataByUrl(dictResource).then(r => {
if (!r.words.length) {
router.push('/word')
return Toast.warning('没有单词可学习!')
}
runtimeStore.editDict = r
if (store.load) {
console.log('直接加载')
store.changeDict(r)
studyData = getCurrentStudyWord()
loading = false
}
})
} else {
router.push('/word')
}
} else {
router.push('/word')
}
loading = true
}
})
useStartKeyboardEventListener()
useDisableEventListener(() => loading)
watch(() => studyData, () => {
if (studyData.new.length === 0) {
if (studyData.review.length) {

View File

@@ -60,7 +60,7 @@ function startStudy() {
custom: store.sdict.custom,
complete: store.sdict.complete,
})
nav('study-word', {name: store.sdict.name, id: store.sdict.id}, currentStudy)
nav('study-word/' + store.sdict.id, {}, currentStudy)
} else {
window.umami?.track('no-dict')
Toast.warning('请先选择一本词典')

View File

@@ -21,11 +21,11 @@ export const routes: RouteRecordRaw[] = [
// {path: 'home', component: HomeIndex},
{path: 'word', component: WordHomePage},
{path: 'dict-list', component: DictList},
{path: 'study-word', component: StudyWord},
{path: 'study-word/:id', component: StudyWord},
{path: 'dict-detail', component: DictDetail},
{path: 'article', component: ArticleHomePage},
{path: 'study-article', component: StudyArticle},
{path: 'study-article/:id', component: StudyArticle},
{path: 'book-detail', component: BookDetail},
{path: 'book-list', component: BookList},
{path: 'edit-article', component: () => import("@/pages/pc/article/EditArticlePage.vue")},
@@ -39,8 +39,8 @@ export const routes: RouteRecordRaw[] = [
]
const router = VueRouter.createRouter({
// history: VueRouter.createWebHistory(),
history: VueRouter.createWebHashHistory(),
history: VueRouter.createWebHistory(),
// history: VueRouter.createWebHashHistory(),
routes,
scrollBehavior(to, from, savedPosition) {
// console.log('savedPosition', savedPosition)

View File

@@ -414,9 +414,9 @@ export async function sleep(time: number) {
export async function _getDictDataByUrl(val: DictResource, type: DictType = DictType.word): Promise<Dict> {
// await sleep(2000);
let dictResourceUrl = `./dicts/${val.language}/word/${val.url}`
let dictResourceUrl = `/dicts/${val.language}/word/${val.url}`
if (type === DictType.article) {
dictResourceUrl = `./dicts/${val.language}/${val.type}/${val.url}`;
dictResourceUrl = `/dicts/${val.language}/${val.type}/${val.url}`;
}
let s = await getDictFile(dictResourceUrl)
if (s) {