This commit is contained in:
Zyronon
2025-10-12 19:53:49 +08:00
parent eac6fd6748
commit cb1016eabd
13 changed files with 112 additions and 69 deletions

View File

@@ -2,7 +2,7 @@ const {SitemapStream, streamToPromise} = require('sitemap')
const {createWriteStream} = require('fs')
const {resolve} = require('path')
const bookList = require('../public/list/article.json')
const dictList = require('../public/list/dictionary.json')
const dictList = require('../public/list/word.json')
// 你的网站域名
const SITE_URL = 'https://2study.top'

View File

@@ -1,6 +1,6 @@
const fs = require("fs");
const bookList = require('../public/list/article.json')
const dictList = require('../public/list/dictionary.json')
const dictList = require('../public/list/word.json')
async function pushUrls() {
// 配置区:改成你的

View File

@@ -1,16 +1,27 @@
import http from "@/utils/http.ts";
import { Dict } from "@/types/types.ts";
import { cloneDeep } from "@/utils";
function remove(data?: any) {
if (data) {
let s = cloneDeep(data)
delete s.words
delete s.articles
delete s.statistics
return s;
}
}
export function dictListVersion() {
return http<number>('dicts/dictListVersion', null, null, 'get')
}
export function myDictList() {
return http('dicts/myDictList', null, null, 'get')
export function myDictList(params?) {
return http('dicts/myDictList', null, params, 'get')
}
export function add2MyDict(data) {
return http('dicts/add2MyDict', null, data, 'get')
return http('dicts/add2MyDict', remove(data), null, 'post')
}
export function addStat(data) {
@@ -22,5 +33,5 @@ export function detail(params?, data?) {
}
export function setDictProp(params?, data?) {
return http<Dict>('dicts/setDictProp', data, params, 'post')
return http<Dict>('dicts/setDictProp', remove(data), remove(params), 'post')
}

View File

@@ -23,8 +23,8 @@ export const RESOURCE_PATH = ENV.API + 'static'
export const DICT_LIST = {
WORD: {
ALL: '/list/dictionary.json',
RECOMMENDED: '/list/recommend_dictionary.json',
ALL: '/list/word.json',
RECOMMENDED: '/list/recommend_word.json',
},
ARTICLE: {
ALL: '/list/article.json',

View File

@@ -18,7 +18,8 @@ import dayjs from "dayjs";
import isBetween from "dayjs/plugin/isBetween";
import isoWeek from 'dayjs/plugin/isoWeek'
import { useFetch } from "@vueuse/core";
import { DICT_LIST, PracticeSaveArticleKey } from "@/config/env.ts";
import { CAN_REQUEST, DICT_LIST, PracticeSaveArticleKey } from "@/config/env.ts";
import { myDictList } from "@/apis";
dayjs.extend(isoWeek)
dayjs.extend(isBetween);
@@ -35,6 +36,12 @@ watch(() => store.load, n => {
}, {immediate: true})
async function init() {
if (CAN_REQUEST) {
let res = await myDictList({type: "article"})
if (res.success) {
store.setState(Object.assign(store.$state, res.data))
}
}
if (store.article.studyIndex >= 1) {
if (!store.sbook.custom && !store.sbook.articles.length) {
store.article.bookList[store.article.studyIndex] = await _getDictDataByUrl(store.sbook, DictType.article)
@@ -156,7 +163,6 @@ const weekList = $computed(() => {
const {data: recommendBookList, isFetching} = useFetch(resourceWrap(DICT_LIST.ARTICLE.RECOMMENDED)).json()
</script>
<template>

View File

@@ -22,7 +22,6 @@ import { useSettingStore } from "@/stores/setting.ts";
import { useFetch } from "@vueuse/core";
import { CAN_REQUEST, DICT_LIST } from "@/config/env.ts";
import { detail } from "@/apis";
import { run } from "vue-tsc";
const runtimeStore = useRuntimeStore()
const settingStore = useSettingStore()
@@ -89,7 +88,6 @@ async function init() {
) {
loading = true
let r = await _getDictDataByUrl(runtimeStore.editDict, DictType.article)
loading = false
runtimeStore.editDict = r
}
@@ -107,6 +105,7 @@ async function init() {
if (runtimeStore.editDict.articles.length) {
selectArticle = runtimeStore.editDict.articles[0]
}
loading = false
}
}
}

View File

@@ -1,11 +1,11 @@
<script setup lang="tsx">
import {DictId} from "@/types/types.ts";
import { DictId } from "@/types/types.ts";
import BasePage from "@/components/BasePage.vue";
import {computed, onMounted, reactive, ref, shallowReactive} from "vue";
import {useRuntimeStore} from "@/stores/runtime.ts";
import {_getDictDataByUrl, _nextTick, convertToWord, loadJsLib, useNav} from "@/utils";
import {nanoid} from "nanoid";
import { computed, onMounted, reactive, ref, shallowReactive } from "vue";
import { useRuntimeStore } from "@/stores/runtime.ts";
import { _getDictDataByUrl, _nextTick, convertToWord, loadJsLib, useNav } from "@/utils";
import { nanoid } from "nanoid";
import BaseIcon from "@/components/BaseIcon.vue";
import BaseTable from "@/components/BaseTable.vue";
import WordItem from "@/components/WordItem.vue";
@@ -13,20 +13,21 @@ import Toast from '@/components/base/toast/Toast.ts'
import PopConfirm from "@/components/PopConfirm.vue";
import BackIcon from "@/components/BackIcon.vue";
import BaseButton from "@/components/BaseButton.vue";
import {useRoute, useRouter} from "vue-router";
import {useBaseStore} from "@/stores/base.ts";
import { useRoute, useRouter } from "vue-router";
import { useBaseStore } from "@/stores/base.ts";
import EditBook from "@/pages/article/components/EditBook.vue";
import {getDefaultDict} from "@/types/func.ts";
import { getDefaultDict } from "@/types/func.ts";
import BaseInput from "@/components/base/BaseInput.vue";
import Textarea from "@/components/base/Textarea.vue";
import FormItem from "@/components/base/form/FormItem.vue";
import Form from "@/components/base/form/Form.vue";
import DeleteIcon from "@/components/icon/DeleteIcon.vue";
import {getCurrentStudyWord} from "@/hooks/dict.ts";
import { getCurrentStudyWord } from "@/hooks/dict.ts";
import PracticeSettingDialog from "@/pages/word/components/PracticeSettingDialog.vue";
import {useSettingStore} from "@/stores/setting.ts";
import {MessageBox} from "@/utils/MessageBox.tsx";
import {Origin} from "@/config/env.ts";
import { useSettingStore } from "@/stores/setting.ts";
import { MessageBox } from "@/utils/MessageBox.tsx";
import { CAN_REQUEST, Origin } from "@/config/env.ts";
import { detail } from "@/apis";
const runtimeStore = useRuntimeStore()
const base = useBaseStore()
@@ -177,7 +178,7 @@ const showBookDetail = computed(() => {
return !(isAdd || isEdit);
})
onMounted(() => {
onMounted(async () => {
if (route.query?.isAdd) {
isAdd = true
runtimeStore.editDict = getDefaultDict()
@@ -187,14 +188,25 @@ onMounted(() => {
} else {
if (!runtimeStore.editDict.words.length
&& !runtimeStore.editDict.custom
&& ![DictId.wordCollect, DictId.wordWrong, DictId.wordKnown].includes(runtimeStore.editDict.id)
&& ![DictId.wordCollect, DictId.wordWrong, DictId.wordKnown].includes(runtimeStore.editDict.en_name || runtimeStore.editDict.id)
) {
loading = true
_getDictDataByUrl(runtimeStore.editDict).then(r => {
loading = false
runtimeStore.editDict = r
})
let r = await _getDictDataByUrl(runtimeStore.editDict)
runtimeStore.editDict = r
}
if (base.word.bookList.find(book => book.id === runtimeStore.editDict.id)) {
if (CAN_REQUEST) {
let res = await detail({id: runtimeStore.editDict.id})
if (res.success) {
runtimeStore.editDict.statistics = res.data.statistics
if (res.data.words.length) {
runtimeStore.editDict.words = res.data.words
}
}
}
}
loading = false
}
}
})
@@ -211,31 +223,26 @@ const settingStore = useSettingStore()
const {nav} = useNav()
//todo 可以和首页合并
function startPractice() {
if (store.sdict.id) {
if (!store.sdict.words.length) {
return Toast.warning('没有单词可学习!')
}
window.umami?.track('startStudyWord', {
name: store.sdict.name,
index: store.sdict.lastLearnIndex,
perDayStudyNumber: store.sdict.perDayStudyNumber,
custom: store.sdict.custom,
complete: store.sdict.complete,
wordPracticeMode: settingStore.wordPracticeMode
})
let currentStudy = getCurrentStudyWord()
nav('practice-words/' + store.sdict.id, {}, currentStudy)
} else {
window.umami?.track('no-dict')
Toast.warning('请先选择一本词典')
}
}
async function addMyStudyList() {
async function startPractice() {
studyLoading = true
await base.changeDict(runtimeStore.editDict)
studyLoading = false
window.umami?.track('startStudyWord', {
name: store.sdict.name,
index: store.sdict.lastLearnIndex,
perDayStudyNumber: store.sdict.perDayStudyNumber,
custom: store.sdict.custom,
complete: store.sdict.complete,
wordPracticeMode: settingStore.wordPracticeMode
})
let currentStudy = getCurrentStudyWord()
nav('practice-words/' + store.sdict.id, {}, currentStudy)
}
async function addMyStudyList() {
if (!runtimeStore.editDict.words.length) {
return Toast.warning('没有单词可学习!')
}
if (!settingStore.disableShowPracticeSettingDialog) {
showPracticeSettingDialog = true
return
@@ -243,7 +250,6 @@ async function addMyStudyList() {
startPractice()
}
let exportLoading = $ref(false)
let importLoading = $ref(false)
let tableRef = ref()

View File

@@ -20,7 +20,8 @@ import ChangeLastPracticeIndexDialog from "@/pages/word/components/ChangeLastPra
import { useSettingStore } from "@/stores/setting.ts";
import CollectNotice from "@/components/CollectNotice.vue";
import { useFetch } from "@vueuse/core";
import { DICT_LIST, PracticeSaveWordKey } from "@/config/env.ts";
import { CAN_REQUEST, DICT_LIST, PracticeSaveWordKey } from "@/config/env.ts";
import { myDictList } from "@/apis";
const store = useBaseStore()
@@ -41,6 +42,12 @@ watch(() => store.load, n => {
}, {immediate: true})
async function init() {
if (CAN_REQUEST) {
let res = await myDictList({type: "word"})
if (res.success) {
store.setState(Object.assign(store.$state, res.data))
}
}
if (store.word.studyIndex >= 3) {
if (!store.sdict.custom && !store.sdict.words.length) {
store.word.bookList[store.word.studyIndex] = await _getDictDataByUrl(store.sdict)
@@ -134,23 +141,26 @@ function check(cb: Function) {
if (!store.sdict.id) {
Toast.warning('请先选择一本词典')
} else {
runtimeStore.editDict = getDefaultDict(store.sdict)
cb()
}
}
function savePracticeSetting() {
async function savePracticeSetting() {
Toast.success('修改成功')
isSaveData = false
localStorage.removeItem(PracticeSaveWordKey.key)
await store.changeDict(runtimeStore.editDict)
currentStudy = getCurrentStudyWord()
}
function saveLastPracticeIndex(e) {
store.sdict.lastLearnIndex = e
showChangeLastPracticeIndexDialog = false
async function saveLastPracticeIndex(e) {
Toast.success('修改成功')
runtimeStore.editDict.lastLearnIndex = e
showChangeLastPracticeIndexDialog = false
isSaveData = false
localStorage.removeItem(PracticeSaveWordKey.key)
await store.changeDict(runtimeStore.editDict)
currentStudy = getCurrentStudyWord()
}

View File

@@ -4,11 +4,13 @@ import BaseTable from "@/components/BaseTable.vue";
import WordItem from "@/components/WordItem.vue";
import {useBaseStore} from "@/stores/base.ts";
import {defineAsyncComponent} from "vue";
import { useRuntimeStore } from "@/stores/runtime.ts";
const Dialog = defineAsyncComponent(() => import('@/components/dialog/Dialog.vue'))
const model = defineModel()
const store = useBaseStore()
const runtimeStore = useRuntimeStore()
defineEmits<{
ok: [number]
}>()
@@ -21,7 +23,7 @@ defineEmits<{
<div class="px-4 pb-4 h-80vh w-30rem">
<BaseTable
class="h-full"
:list='store.sdict.words'
:list='runtimeStore.editDict.words'
:loading='false'
:show-toolbar="false"
>

View File

@@ -12,11 +12,13 @@ import {useSettingStore} from "@/stores/setting.ts";
import Toast from "@/components/base/toast/Toast.ts";
import ChangeLastPracticeIndexDialog from "@/pages/word/components/ChangeLastPracticeIndexDialog.vue";
import Tooltip from "@/components/base/Tooltip.vue";
import { useRuntimeStore } from "@/stores/runtime.ts";
const Dialog = defineAsyncComponent(() => import('@/components/dialog/Dialog.vue'))
const store = useBaseStore()
const settings = useSettingStore()
const runtimeStore = useRuntimeStore()
const model = defineModel()
@@ -36,8 +38,8 @@ let tempDisableShowPracticeSettingDialog = $ref(false)
function changePerDayStudyNumber() {
store.sdict.perDayStudyNumber = tempPerDayStudyNumber
store.sdict.lastLearnIndex = tempLastLearnIndex
runtimeStore.editDict.perDayStudyNumber = tempPerDayStudyNumber
runtimeStore.editDict.lastLearnIndex = tempLastLearnIndex
settings.wordPracticeMode = temPracticeMode
settings.disableShowPracticeSettingDialog = tempDisableShowPracticeSettingDialog
emit('ok')
@@ -45,9 +47,9 @@ function changePerDayStudyNumber() {
watch(() => model.value, (n) => {
if (n) {
if (store.sdict.id) {
tempPerDayStudyNumber = store.sdict.perDayStudyNumber
tempLastLearnIndex = store.sdict.lastLearnIndex
if (runtimeStore.editDict.id) {
tempPerDayStudyNumber = runtimeStore.editDict.perDayStudyNumber
tempLastLearnIndex = runtimeStore.editDict.lastLearnIndex
temPracticeMode = settings.wordPracticeMode
tempDisableShowPracticeSettingDialog = settings.disableShowPracticeSettingDialog
} else {
@@ -66,7 +68,7 @@ watch(() => model.value, (n) => {
<span>每日<span class="text-3xl mx-2 lh">{{ tempPerDayStudyNumber }}</span></span>
<span>预计<span
class="text-3xl mx-2 lh">{{
_getAccomplishDays(store.sdict.length - tempLastLearnIndex, tempPerDayStudyNumber)
_getAccomplishDays(runtimeStore.editDict.length - tempLastLearnIndex, tempPerDayStudyNumber)
}}</span>天完成</span>
</div>
<div class="flex mb-4 gap-space">
@@ -84,7 +86,7 @@ watch(() => model.value, (n) => {
:step="10"
show-text
class="my-1"
:max="store.sdict.words.length" v-model="tempLastLearnIndex"/>
:max="runtimeStore.editDict.words.length" v-model="tempLastLearnIndex"/>
<BaseButton @click="show = true">从词典选起始位置</BaseButton>
</div>
</div>

View File

@@ -146,7 +146,13 @@ export const useBaseStore = defineStore('base', {
})
},
//改变词典
changeDict(val: Dict) {
async changeDict(val: Dict) {
if (CAN_REQUEST) {
let r = await add2MyDict(val)
if (!r.success) {
return Toast.error(r.msg)
}
}
//把其他的词典的单词数据都删掉,全保存在内存里太卡了
this.word.bookList.slice(3).map(v => {
if (!v.custom) {
@@ -161,6 +167,7 @@ export const useBaseStore = defineStore('base', {
this.word.studyIndex = rIndex
this.word.bookList[this.word.studyIndex].words = shallowReactive(val.words)
this.word.bookList[this.word.studyIndex].perDayStudyNumber = val.perDayStudyNumber
this.word.bookList[this.word.studyIndex].lastLearnIndex = val.lastLearnIndex
} else {
this.word.bookList.push(getDefaultDict(val))
this.word.studyIndex = this.word.bookList.length - 1
@@ -169,7 +176,7 @@ export const useBaseStore = defineStore('base', {
//改变书籍
async changeBook(val: Dict) {
if (CAN_REQUEST) {
let r = await add2MyDict({id: val.id, switch: true})
let r = await add2MyDict(val)
if (!r.success) {
return Toast.error(r.msg)
}