save
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
[
|
||||
[
|
||||
{
|
||||
"id": "cet4",
|
||||
"name": "CET-4",
|
||||
@@ -675,9 +674,9 @@
|
||||
"length": 1665,
|
||||
"language": "en",
|
||||
"translateLanguage": "zh-CN"
|
||||
}
|
||||
],
|
||||
[
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"id": "pet-2024",
|
||||
"name": "PET-2024",
|
||||
@@ -1873,9 +1872,9 @@
|
||||
"length": 438,
|
||||
"language": "en",
|
||||
"translateLanguage": "zh-CN"
|
||||
}
|
||||
],
|
||||
[
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"id": "gaokao3500",
|
||||
"name": "高考 3500 词",
|
||||
@@ -3257,5 +3256,4 @@
|
||||
"language": "en",
|
||||
"translateLanguage": "zh-CN"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -1,9 +1,26 @@
|
||||
import http from "@/utils/http.ts";
|
||||
|
||||
export function officialList() {
|
||||
return http('dicts/officialList', null, null, 'get')
|
||||
}
|
||||
import { Dict } from "@/types/types.ts";
|
||||
|
||||
export function dictListVersion() {
|
||||
return http<number>('dicts/dictListVersion', null, null, 'get')
|
||||
}
|
||||
|
||||
export function myDictList() {
|
||||
return http('dicts/myDictList', null, null, 'get')
|
||||
}
|
||||
|
||||
export function add2MyDict(data) {
|
||||
return http('dicts/add2MyDict', null, data, 'get')
|
||||
}
|
||||
|
||||
export function addStat(data) {
|
||||
return http('dicts/addStat', data, null, 'post')
|
||||
}
|
||||
|
||||
export function detail(params?, data?) {
|
||||
return http<Dict>('dicts/detail', data, params, 'get')
|
||||
}
|
||||
|
||||
export function setDictProp(params?, data?) {
|
||||
return http<Dict>('dicts/setDictProp', data, params, 'post')
|
||||
}
|
||||
|
||||
@@ -5,13 +5,13 @@ import { nextTick, watch } from 'vue'
|
||||
const props = withDefaults(defineProps<{
|
||||
list?: any[],
|
||||
activeIndex?: number,
|
||||
activeId?: string,
|
||||
activeId?: number,
|
||||
isActive?: boolean
|
||||
static?: boolean
|
||||
}>(), {
|
||||
list: [],
|
||||
activeIndex: -1,
|
||||
activeId: '',
|
||||
activeId: null,
|
||||
isActive: false,
|
||||
static: true
|
||||
})
|
||||
|
||||
@@ -17,6 +17,8 @@ const map = {
|
||||
|
||||
export const ENV = Object.assign(map['DEV'], common)
|
||||
export const IS_OFFICIAL = import.meta.env.DEV
|
||||
export const IS_LOGIN = true
|
||||
export const CAN_REQUEST = IS_LOGIN && IS_OFFICIAL
|
||||
export const RESOURCE_PATH = ENV.API + 'static'
|
||||
|
||||
export const DICT_LIST = {
|
||||
|
||||
@@ -53,7 +53,6 @@ export function useEventListener(type: string, listener: EventListenerOrEventLis
|
||||
}
|
||||
})
|
||||
const remove = () => {
|
||||
console.log('onUnmounted')
|
||||
if (isMobile()) {
|
||||
let s = document.querySelector('#typing-listener')
|
||||
if (s) {
|
||||
|
||||
@@ -155,6 +155,8 @@ const weekList = $computed(() => {
|
||||
|
||||
const {data: recommendBookList, isFetching} = useFetch(resourceWrap(DICT_LIST.ARTICLE.RECOMMENDED)).json()
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -20,7 +20,9 @@ import ArticleAudio from "@/pages/article/components/ArticleAudio.vue";
|
||||
import { MessageBox } from "@/utils/MessageBox.tsx";
|
||||
import { useSettingStore } from "@/stores/setting.ts";
|
||||
import { useFetch } from "@vueuse/core";
|
||||
import { DICT_LIST } from "@/config/env.ts";
|
||||
import { CAN_REQUEST, DICT_LIST } from "@/config/env.ts";
|
||||
import { detail } from "@/apis";
|
||||
import { run } from "vue-tsc";
|
||||
|
||||
const runtimeStore = useRuntimeStore()
|
||||
const settingStore = useSettingStore()
|
||||
@@ -57,7 +59,7 @@ async function addMyStudyList() {
|
||||
}
|
||||
|
||||
studyLoading = true
|
||||
base.changeBook(sbook)
|
||||
await base.changeBook(sbook)
|
||||
studyLoading = false
|
||||
|
||||
window.umami?.track('startStudyArticle', {
|
||||
@@ -83,17 +85,28 @@ async function init() {
|
||||
} else {
|
||||
if (!runtimeStore.editDict?.articles?.length
|
||||
&& !runtimeStore.editDict?.custom
|
||||
&& ![DictId.articleCollect].includes(runtimeStore.editDict.id)
|
||||
&& ![DictId.articleCollect].includes(runtimeStore.editDict.en_name || runtimeStore.editDict.id)
|
||||
) {
|
||||
loading = true
|
||||
let r = await _getDictDataByUrl(runtimeStore.editDict, DictType.article)
|
||||
loading = false
|
||||
runtimeStore.editDict = r
|
||||
}
|
||||
|
||||
if (base.article.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.articles.length){
|
||||
runtimeStore.editDict.articles = res.data.articles
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (runtimeStore.editDict.articles.length) {
|
||||
selectArticle = runtimeStore.editDict.articles[0]
|
||||
}
|
||||
console.log('runtimeStore.editDict', runtimeStore.editDict)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,9 +34,12 @@ import { useRoute, useRouter } from "vue-router";
|
||||
import PracticeLayout from "@/components/PracticeLayout.vue";
|
||||
import ArticleAudio from "@/pages/article/components/ArticleAudio.vue";
|
||||
import VolumeSetting from "@/pages/article/components/VolumeSetting.vue";
|
||||
import { DICT_LIST, PracticeSaveArticleKey } from "@/config/env.ts";
|
||||
import { CAN_REQUEST, DICT_LIST, PracticeSaveArticleKey } from "@/config/env.ts";
|
||||
import { addStat, setDictProp } from "@/apis";
|
||||
import { useRuntimeStore } from "@/stores/runtime.ts";
|
||||
|
||||
const store = useBaseStore()
|
||||
const runtimeStore = useRuntimeStore()
|
||||
const settingStore = useSettingStore()
|
||||
const statStore = usePracticeStore()
|
||||
const {toggleTheme} = useTheme()
|
||||
@@ -106,10 +109,10 @@ async function init() {
|
||||
let dictId = route.params.id
|
||||
if (dictId) {
|
||||
//先在自己的词典列表里面找,如果没有再在资源列表里面找
|
||||
dict = store.article.bookList.find(v => v.id === dictId)
|
||||
dict = store.article.bookList.find(v => v.id == dictId)
|
||||
let r = await fetch(resourceWrap(DICT_LIST.ARTICLE.ALL))
|
||||
let book_list = await r.json()
|
||||
if (!dict) dict = book_list.flat().find(v => v.id === dictId) as Dict
|
||||
if (!dict) dict = book_list.find(v => v.id === dictId) as Dict
|
||||
if (dict && dict.id) {
|
||||
//如果是不是自定义词典,就请求数据
|
||||
if (!dict.custom) dict = await _getDictDataByUrl(dict, DictType.article)
|
||||
@@ -117,7 +120,7 @@ async function init() {
|
||||
router.push('/articles')
|
||||
return Toast.warning('没有文章可学习!')
|
||||
}
|
||||
store.changeBook(dict)
|
||||
await store.changeBook(dict)
|
||||
articleData.list = cloneDeep(store.sbook.articles)
|
||||
getCurrentPractice()
|
||||
loading = false
|
||||
@@ -143,6 +146,7 @@ onMounted(() => {
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
runtimeStore.disableEventListener = false
|
||||
clearInterval(timer)
|
||||
savePracticeData(true, false)
|
||||
})
|
||||
@@ -234,21 +238,29 @@ function setArticle(val: Article) {
|
||||
})
|
||||
}
|
||||
|
||||
function complete() {
|
||||
async function complete() {
|
||||
clearInterval(timer)
|
||||
setTimeout(() => {
|
||||
localStorage.removeItem(PracticeSaveArticleKey.key)
|
||||
}, 1500)
|
||||
|
||||
//todo 有空了改成实时保存
|
||||
let data: Partial<Statistics> & { title: string, id: string } = {
|
||||
id: articleData.article.id,
|
||||
let data: Partial<Statistics> & { title: string, articleId: number } = {
|
||||
articleId: articleData.article.id,
|
||||
title: articleData.article.title,
|
||||
spend: statStore.spend,
|
||||
startDate: statStore.startDate,
|
||||
total: statStore.total,
|
||||
wrong: statStore.wrong,
|
||||
}
|
||||
|
||||
if (CAN_REQUEST) {
|
||||
let res = await addStat({...data, type: 'article'})
|
||||
if (!res.success) {
|
||||
Toast.error(res.msg)
|
||||
}
|
||||
}
|
||||
|
||||
let reportData = {
|
||||
name: store.sbook.name,
|
||||
index: store.sbook.lastLearnIndex,
|
||||
@@ -271,7 +283,6 @@ function getCurrentPractice() {
|
||||
emitter.emit(EventKey.resetWord)
|
||||
let currentArticle = articleData.list[store.sbook.lastLearnIndex]
|
||||
let article = getDefaultArticle(currentArticle)
|
||||
// console.log('article', article)
|
||||
if (article.sections.length) {
|
||||
setArticle(article)
|
||||
} else {
|
||||
@@ -320,11 +331,18 @@ function nextWord(word: ArticleWord) {
|
||||
}
|
||||
}
|
||||
|
||||
function changeArticle(val: ArticleItem) {
|
||||
async function changeArticle(val: ArticleItem) {
|
||||
let rIndex = articleData.list.findIndex(v => v.id === val.item.id)
|
||||
if (rIndex > -1) {
|
||||
store.sbook.lastLearnIndex = rIndex
|
||||
getCurrentPractice()
|
||||
|
||||
if (CAN_REQUEST) {
|
||||
let res = await setDictProp(null, store.sbook)
|
||||
if (!res.success) {
|
||||
Toast.error(res.msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,11 +51,12 @@ const {data: dict_list, isFetching} = useFetch(resourceWrap(DICT_LIST.WORD.ALL))
|
||||
const groupedByCategoryAndTag = $computed(() => {
|
||||
let data = []
|
||||
if (!dict_list.value) return data
|
||||
const groupByCategory = groupBy(dict_list.value.flat(), 'category')
|
||||
const groupByCategory = groupBy(dict_list.value, 'category')
|
||||
for (const [key, value] of Object.entries(groupByCategory)) {
|
||||
data.push([key, groupByDictTags(value)])
|
||||
}
|
||||
[data[2], data[3]] = [data[3], data[2]];
|
||||
console.log('data',data)
|
||||
return data
|
||||
})
|
||||
|
||||
@@ -65,7 +66,7 @@ let searchKey = $ref('')
|
||||
const searchList = computed<any[]>(() => {
|
||||
if (searchKey) {
|
||||
let s = searchKey.toLowerCase()
|
||||
return dict_list.value.flat().filter((item) => {
|
||||
return dict_list.value.filter((item) => {
|
||||
return item.id.toLowerCase().includes(s)
|
||||
|| item.name.toLowerCase().includes(s)
|
||||
|| item.category.toLowerCase().includes(s)
|
||||
|
||||
@@ -4,8 +4,9 @@ import { _getStudyProgress, checkAndUpgradeSaveDict, shakeCommonDict } from "@/u
|
||||
import { shallowReactive } from "vue";
|
||||
import { getDefaultDict } from "@/types/func.ts";
|
||||
import { get, set } from 'idb-keyval'
|
||||
import { IS_OFFICIAL, SAVE_DICT_KEY } from "@/config/env.ts";
|
||||
import { dictListVersion } from "@/apis";
|
||||
import { CAN_REQUEST, IS_LOGIN, IS_OFFICIAL, SAVE_DICT_KEY } from "@/config/env.ts";
|
||||
import { add2MyDict, dictListVersion, myDictList } from "@/apis";
|
||||
import Toast from "@/components/base/toast/Toast.ts";
|
||||
|
||||
export interface BaseState {
|
||||
simpleWords: string[],
|
||||
@@ -36,18 +37,6 @@ export const DefaultBaseState = (): BaseState => ({
|
||||
getDefaultDict({id: DictId.wordCollect, name: '收藏'}),
|
||||
getDefaultDict({id: DictId.wordWrong, name: '错词'}),
|
||||
getDefaultDict({id: DictId.wordKnown, name: '已掌握', description: '已掌握后的单词不会出现在练习中'}),
|
||||
// getDefaultDict({
|
||||
// id: 'nce-new-2',
|
||||
// name: '新概念英语(新版)-2',
|
||||
// description: '新概念英语新版第二册',
|
||||
// category: '青少年英语',
|
||||
// tags: ['新概念英语'],
|
||||
// url: 'nce-new-2_v2.json',
|
||||
// length: 862,
|
||||
// translateLanguage: 'common',
|
||||
// language: 'en',
|
||||
// type: DictType.word
|
||||
// }),
|
||||
],
|
||||
studyIndex: -1,
|
||||
},
|
||||
@@ -137,7 +126,16 @@ export const useBaseStore = defineStore('base', {
|
||||
let configStr: string = await get(SAVE_DICT_KEY.key)
|
||||
let data = checkAndUpgradeSaveDict(configStr)
|
||||
if (IS_OFFICIAL) {
|
||||
data.dictListVersion = await dictListVersion()
|
||||
let r = await dictListVersion()
|
||||
if (r.success) {
|
||||
data.dictListVersion = r.data
|
||||
}
|
||||
}
|
||||
if (CAN_REQUEST) {
|
||||
let res = await myDictList()
|
||||
if (res.success) {
|
||||
Object.assign(data, res.data)
|
||||
}
|
||||
}
|
||||
this.setState(data)
|
||||
set(SAVE_DICT_KEY.key, JSON.stringify({val: shakeCommonDict(this.$state), version: SAVE_DICT_KEY.version}))
|
||||
@@ -169,7 +167,13 @@ export const useBaseStore = defineStore('base', {
|
||||
}
|
||||
},
|
||||
//改变书籍
|
||||
changeBook(val: Dict) {
|
||||
async changeBook(val: Dict) {
|
||||
if (CAN_REQUEST) {
|
||||
let r = await add2MyDict({id: val.id, switch: true})
|
||||
if (!r.success) {
|
||||
return Toast.error(r.msg)
|
||||
}
|
||||
}
|
||||
//把其他的书籍里面的文章数据都删掉,全保存在内存里太卡了
|
||||
this.article.bookList.slice(1).map(v => {
|
||||
if (!v.custom) {
|
||||
|
||||
@@ -35,7 +35,7 @@ export function getDefaultArticleWord(val: Partial<ArticleWord> = {}): ArticleWo
|
||||
|
||||
export function getDefaultArticle(val: Partial<Article> = {}): Article {
|
||||
return {
|
||||
id: '',
|
||||
id: null,
|
||||
title: '',
|
||||
titleTranslate: '',
|
||||
text: '',
|
||||
|
||||
@@ -66,7 +66,7 @@ export interface Sentence {
|
||||
}
|
||||
|
||||
export interface Article {
|
||||
id: string,
|
||||
id?: number,
|
||||
title: string,
|
||||
titleTranslate: string,
|
||||
text: string,
|
||||
@@ -150,6 +150,7 @@ export type DictResource = {
|
||||
name: string
|
||||
description: string
|
||||
url: string
|
||||
en_name?: string
|
||||
length: number
|
||||
category: string
|
||||
tags: string[]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import axios, { AxiosInstance, AxiosResponse } from 'axios'
|
||||
import axios, { AxiosInstance } from 'axios'
|
||||
import { ENV } from "@/config/env.ts";
|
||||
import Toast from "@/components/base/toast/Toast.ts";
|
||||
|
||||
@@ -21,7 +21,6 @@ axiosInstance.interceptors.request.use(
|
||||
axiosInstance.interceptors.response.use(
|
||||
// 响应正常的处理
|
||||
(response) => {
|
||||
// console.log(response)
|
||||
// console.log(response.data)
|
||||
const {data} = response
|
||||
if (response.status !== 200) {
|
||||
@@ -30,33 +29,42 @@ axiosInstance.interceptors.response.use(
|
||||
}
|
||||
if (data === null) {
|
||||
return Promise.resolve({
|
||||
code: '009900',
|
||||
code: 500,
|
||||
msg: '系统出现错误',
|
||||
data: {},
|
||||
success: false,
|
||||
})
|
||||
}
|
||||
if (typeof data !== 'object') {
|
||||
return Promise.resolve({
|
||||
data,
|
||||
success: true,
|
||||
code: 200
|
||||
})
|
||||
}
|
||||
return Promise.resolve(data)
|
||||
},
|
||||
// 请求出错的处理
|
||||
(error) => {
|
||||
console.log(error)
|
||||
if (error.response === undefined && error.status === undefined) {
|
||||
return Promise.resolve({
|
||||
code: '009900',
|
||||
code: 500,
|
||||
msg: '服务器响应超时',
|
||||
data: null,
|
||||
success: false,
|
||||
})
|
||||
}
|
||||
if (error.response.status >= 500) {
|
||||
return Promise.resolve({
|
||||
code: '009900',
|
||||
code: 500,
|
||||
msg: '服务器出现错误',
|
||||
data: null,
|
||||
success: false,
|
||||
})
|
||||
}
|
||||
if (error.response.status === 401) {
|
||||
return Promise.resolve({
|
||||
code: '009900',
|
||||
code: 500,
|
||||
msg: '用户名或密码不正确',
|
||||
data: null,
|
||||
})
|
||||
@@ -66,18 +74,21 @@ axiosInstance.interceptors.response.use(
|
||||
return Promise.resolve({
|
||||
code: data.code,
|
||||
msg: data.msg,
|
||||
success: false,
|
||||
})
|
||||
}
|
||||
return Promise.resolve({
|
||||
code: '009900',
|
||||
code: 500,
|
||||
success: false,
|
||||
msg: data.msg,
|
||||
data: null,
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
type AxiosResponse<T> = { code: number, data: T, success: boolean, msg: string }
|
||||
|
||||
async function request<T>(url, data = {}, params = {}, method): Promise<T> {
|
||||
async function request<T>(url, data = {}, params = {}, method): Promise<AxiosResponse<T>> {
|
||||
return axiosInstance({
|
||||
url: '/v1/' + url,
|
||||
method,
|
||||
|
||||
Reference in New Issue
Block a user