fix:generate-sitemap
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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
43
src/assets/book-list.json
Normal 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
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
@@ -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('请先选择一本书籍')
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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('请先选择一本词典')
|
||||
|
||||
@@ -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")},
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"),
|
||||
|
||||
Reference in New Issue
Block a user