fix:generate-sitemap

This commit is contained in:
zyronon
2025-08-20 00:23:37 +08:00
parent f78624799d
commit 6c4bfb4ec3
16 changed files with 3389 additions and 2904 deletions

View File

@@ -6,7 +6,7 @@
"start": "vite",
"dev": "vite",
"test": "",
"build": "vite build",
"build": "vite build && node scripts/generate-sitemap.js",
"build-nocdn": "vite build",
"build-tsc": "vue-tsc && vite build",
"report": "vite build",
@@ -14,7 +14,8 @@
"commit": "git-cz",
"prepare": "husky install",
"i18n:write": "gulp i18nwrite",
"deploy-oss": "node scripts/deploy-oss.js"
"deploy-oss": "node scripts/deploy-oss.js",
"deploy-2": "node scripts/generate-sitemap.js"
},
"dependencies": {
"@imengyu/vue3-context-menu": "^1.5.1",

View File

@@ -1,24 +1,25 @@
const {SitemapStream, streamToPromise} = require('sitemap')
const {createWriteStream} = require('fs')
const {resolve} = require('path')
const bookList = require('../src/assets/book-list.json')
const dictList = require('../src/assets/dict-list.json')
// 你的网站域名
const SITE_URL = 'https://yourdomain.com'
const SITE_URL = 'https://2study.top'
// 静态路由(首页、练习页等)
const staticPages = [
{url: '/', changefreq: 'daily', priority: 1.0},
{url: '/word', changefreq: 'daily', priority: 0.9},
{url: '/article', changefreq: 'daily', priority: 0.9},
{url: '/words', changefreq: 'daily', priority: 0.9},
{url: '/articles', 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 自动生成数组
]
const dynamicPages = bookList.flat().map(book => {
return {url: '/practice-articles/' + book.id, changefreq: 'weekly', priority: 0.8}
}).concat(dictList.flat().map(book => {
return {url: '/practice-words/' + book.id, changefreq: 'weekly', priority: 0.8}
}))
async function generateSitemap() {
const sitemap = new SitemapStream({hostname: SITE_URL})

43
src/assets/book-list.json Normal file
View File

@@ -0,0 +1,43 @@
[
[
{
"id": "article_nce2",
"name": "新概念英语2-课文",
"description": "新概念英语2-课文",
"category": "文章学习",
"tags": [
"新概念英语"
],
"url": "NCE_2.json",
"length": 96,
"translateLanguage": "common",
"language": "en"
},
{
"id": "article_nce3",
"name": "新概念英语3-课文",
"description": "新概念英语3-课文",
"category": "文章学习",
"tags": [
"新概念英语"
],
"url": "NCE_3.json",
"length": 3,
"translateLanguage": "common",
"language": "en"
},
{
"id": "article_nce4",
"name": "新概念英语4-课文",
"description": "新概念英语4-课文",
"category": "文章学习",
"tags": [
"新概念英语"
],
"url": "NCE_4.json",
"length": 1,
"translateLanguage": "common",
"language": "en"
}
]
]

3297
src/assets/dict-list.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -43,7 +43,7 @@ function startStudy() {
custom: base.sbook.custom,
complete: base.sbook.complete,
})
nav('/study-article/' + store.sbook.id)
nav('/practice-articles/' + store.sbook.id)
} else {
window.umami?.track('no-book')
Toast.warning('请先选择一本书籍')

View File

@@ -52,7 +52,7 @@ async function init() {
runtimeStore.editDict = getDefaultDict()
} else {
if (!runtimeStore.editDict.id) {
await router.push("/article")
await router.push("/articles")
} else {
if (!runtimeStore.editDict?.articles?.length
&& !runtimeStore.editDict?.custom
@@ -66,7 +66,7 @@ async function init() {
if (runtimeStore.editDict.articles.length) {
selectArticle = runtimeStore.editDict.articles[0]
}
console.log(runtimeStore.editDict)
console.log('runtimeStore.editDict',runtimeStore.editDict)
}
}
}

View File

@@ -10,7 +10,7 @@ import BaseButton from "@/components/BaseButton.vue";
import DictList from "@/pages/pc/components/list/DictList.vue";
import BackIcon from "@/pages/pc/components/BackIcon.vue";
import {useRouter} from "vue-router";
import {enArticle} from "@/assets/dictionary.ts";
import book_list from "@/assets/book-list.json";
import {computed} from "vue";
import {getDefaultDict} from "@/types/func.ts";
@@ -34,7 +34,7 @@ let searchKey = $ref('')
const searchList = computed<any[]>(() => {
if (searchKey) {
let s = searchKey.toLowerCase()
return enArticle.filter((item) => {
return book_list.flat().filter((item) => {
return item.id.toLowerCase().includes(s)
|| item.name.toLowerCase().includes(s)
|| item.category.toLowerCase().includes(s)
@@ -59,7 +59,7 @@ const searchList = computed<any[]>(() => {
<div class="py-1 flex flex-1 justify-end" v-else>
<span class="page-title absolute w-full center">书籍列表</span>
<BaseIcon @click="showSearchInput = true"
class="z-1">
class="z-1">
<IconFluentSearch24Regular/>
</BaseIcon>
</div>
@@ -75,9 +75,9 @@ const searchList = computed<any[]>(() => {
</div>
<div class="w-full mt-2" v-else>
<DictList
v-if="enArticle.length "
v-if="book_list.flat().length "
@selectDict="selectDict"
:list="enArticle"
:list="book_list.flat()"
quantifier="篇"
:select-id="'-1'"/>
</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 {getCurrentStudyWord, useArticleOptions} from "@/hooks/dict.ts";
import {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,9 +20,8 @@ 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 {dictionaryResources, enArticle} from "@/assets/dictionary.ts";
import {useRoute, useRouter} from "vue-router";
import {useRuntimeStore} from "@/stores/runtime.ts";
import book_list from "@/assets/book-list.json";
const store = useBaseStore()
const settingStore = useSettingStore()
@@ -95,12 +94,12 @@ async function init() {
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 = book_list.flat().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')
router.push('/articles')
return Toast.warning('没有文章可学习!')
}
store.changeBook(dict)
@@ -108,10 +107,10 @@ async function init() {
getCurrentPractice()
loading = false
} else {
router.push('/article')
router.push('/articles')
}
} else {
router.push('/article')
router.push('/articles')
}
}

View File

@@ -22,11 +22,11 @@ const {toggleTheme} = useTheme()
<div class="aside anim fixed" :class="{'expand':settingStore.sideExpand}">
<div class="top">
<Logo v-if="settingStore.sideExpand"/>
<div class="row" @click="router.push('/word')">
<div class="row" @click="router.push('/words')">
<IconMaterialSymbolsLightDictionaryOutlineSharp/>
<span v-if="settingStore.sideExpand">单词</span>
</div>
<div class="row" @click="router.push('/article')">
<div class="row" @click="router.push('/articles')">
<IconPhArticleNyTimes/>
<span v-if="settingStore.sideExpand">文章</span>
</div>

View File

@@ -12,9 +12,9 @@ import BackIcon from "@/pages/pc/components/BackIcon.vue";
import DictGroup from "@/pages/pc/components/list/DictGroup.vue";
import {useBaseStore} from "@/stores/base.ts";
import {useRouter} from "vue-router";
import {dictionaryResources} from "@/assets/dictionary.ts";
import {computed} from "vue";
import {getDefaultDict} from "@/types/func.ts";
import dict_list from "@/assets/dict-list.json";
const {nav} = useNav()
const runtimeStore = useRuntimeStore()
@@ -46,7 +46,7 @@ function groupByDictTags(dictList: DictResource[]) {
}
const groupedByCategoryAndTag = $computed(() => {
const groupByCategory = groupBy(dictionaryResources, 'category')
const groupByCategory = groupBy(dict_list.flat(), 'category')
let data = []
for (const [key, value] of Object.entries(groupByCategory)) {
data.push([key, groupByDictTags(value)])
@@ -60,7 +60,7 @@ let searchKey = $ref('')
const searchList = computed<any[]>(() => {
if (searchKey) {
let s = searchKey.toLowerCase()
return dictionaryResources.filter((item) => {
return dict_list.flat().filter((item) => {
return item.id.toLowerCase().includes(s)
|| item.name.toLowerCase().includes(s)
|| item.category.toLowerCase().includes(s)

View File

@@ -21,10 +21,10 @@ import TypeWord from "@/pages/pc/word/components/TypeWord.vue";
import Empty from "@/components/Empty.vue";
import {useBaseStore} from "@/stores/base.ts";
import {usePracticeStore} from "@/stores/practice.ts";
import {dictionaryResources} from "@/assets/dictionary.ts";
import Toast from '@/pages/pc/components/base/toast/Toast.ts'
import {getDefaultDict, getDefaultWord} from "@/types/func.ts";
import ConflictNotice from "@/pages/pc/components/ConflictNotice.vue";
import dict_list from "@/assets/dict-list.json";
interface IProps {
new: Word[],
@@ -68,7 +68,7 @@ async function init() {
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 = dict_list.flat().find(v => v.id === dictId) as Dict
if (dict && dict.id) {
//如果是不是自定义词典,就请求数据
if (!dict.custom) dict = await _getDictDataByUrl(dict)

View File

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

View File

@@ -19,13 +19,17 @@ export const routes: RouteRecordRaw[] = [
redirect: '/word',
children: [
// {path: 'home', component: HomeIndex},
{path: 'word', component: WordHomePage},
{path: 'words', component: WordHomePage},
{path: 'word', redirect: '/words'},
{path: 'dict-list', component: DictList},
{path: 'study-word/:id', component: StudyWord},
{path: 'practice-words/:id', component: StudyWord},
{path: 'study-word', redirect: '/word'},
{path: 'dict-detail', component: DictDetail},
{path: 'article', component: ArticleHomePage},
{path: 'study-article/:id', component: StudyArticle},
{path: 'articles', component: ArticleHomePage},
{path: 'article', redirect: '/articles'},
{path: 'practice-articles/:id', component: StudyArticle},
{path: 'study-article', redirect: '/article'},
{path: 'book-detail', component: BookDetail},
{path: 'book-list', component: BookList},
{path: 'edit-article', component: () => import("@/pages/pc/article/EditArticlePage.vue")},

View File

@@ -8,10 +8,11 @@ import dayjs from 'dayjs'
import axios from "axios";
import {env} from "@/config/ENV.ts";
import {nextTick} from "vue";
import {dictionaryResources, enArticle} from "@/assets/dictionary.ts";
import Toast from '@/pages/pc/components/base/toast/Toast.ts'
import {getDefaultArticle, getDefaultDict, getDefaultWord} from "@/types/func.ts";
import {set} from "idb-keyval";
import book_list from "@/assets/book-list.json";
import dict_list from "@/assets/dict-list.json";
export function no() {
Toast.warning('未现实')
@@ -148,7 +149,7 @@ export function checkAndUpgradeSaveDict(val: any) {
if (currentDictId === studyDictId) defaultState.word.studyIndex = defaultState.word.bookList.length - 1
} else {
//当时把选中的词典的id设为随机了导致通过id找不到
let r = dictionaryResources.find(a => a.name === v.name)
let r: any = dict_list.flat().find(a => a.name === v.name)
if (r) {
formatWord(v)
let dict = getDefaultDict(r)
@@ -169,7 +170,7 @@ export function checkAndUpgradeSaveDict(val: any) {
if (currentDictId === studyDictId) defaultState.article.studyIndex = defaultState.article.bookList.length - 1
} else {
//当时把选中的词典的id设为随机了
let r = enArticle.find(a => a.name === v.name)
let r: any = book_list.flat().find(a => a.name === v.name)
if (r) {
formatWord(v)
let dict = getDefaultDict(r)
@@ -416,7 +417,7 @@ export async function _getDictDataByUrl(val: DictResource, type: DictType = Dict
// await sleep(2000);
let dictResourceUrl = `/dicts/${val.language}/word/${val.url}`
if (type === DictType.article) {
dictResourceUrl = `/dicts/${val.language}/${val.type}/${val.url}`;
dictResourceUrl = `/dicts/${val.language}/article/${val.url}`;
}
let s = await getDictFile(dictResourceUrl)
if (s) {

View File

@@ -106,7 +106,7 @@ export default defineConfig(() => {
LATEST_COMMIT_HASH: JSON.stringify(latestCommitHash + (process.env.NODE_ENV === 'production' ? '' : ' (dev)')),
},
//默认是'',导致只能在一级域名下使用。
base: './',
base: '/',
resolve: {
alias: {
"@": pathResolve("src"),