This commit is contained in:
Zyronon
2025-10-11 00:48:32 +08:00
parent eae79387e2
commit e4f030a7a2
33 changed files with 359 additions and 489 deletions

1
components.d.ts vendored
View File

@@ -73,7 +73,6 @@ declare module 'vue' {
IconFluentSearch24Regular: typeof import('~icons/fluent/search24-regular')['default']
IconFluentSettings20Regular: typeof import('~icons/fluent/settings20-regular')['default']
IconFluentShieldQuestion20Regular: typeof import('~icons/fluent/shield-question20-regular')['default']
IconFluentSpeaker220Regular: typeof import('~icons/fluent/speaker220-regular')['default']
IconFluentSpeakerEdit20Regular: typeof import('~icons/fluent/speaker-edit20-regular')['default']
IconFluentSpeakerSettings20Regular: typeof import('~icons/fluent/speaker-settings20-regular')['default']
IconFluentStar12Regular: typeof import('~icons/fluent/star12-regular')['default']

View File

@@ -18,6 +18,7 @@
},
"dependencies": {
"@imengyu/vue3-context-menu": "^1.5.1",
"@vueuse/core": "14.0.0-alpha.0",
"axios": "^1.10.0",
"compromise": "^14.14.4",
"copy-to-clipboard": "^3.3.3",

98
pnpm-lock.yaml generated
View File

@@ -11,6 +11,9 @@ importers:
'@imengyu/vue3-context-menu':
specifier: ^1.5.1
version: 1.5.2
'@vueuse/core':
specifier: 14.0.0-alpha.0
version: 14.0.0-alpha.0(vue@3.5.18(typescript@5.9.2))
axios:
specifier: ^1.10.0
version: 1.11.0
@@ -161,7 +164,7 @@ importers:
version: 29.0.0(@babel/parser@7.28.3)(vue@3.5.18(typescript@5.9.2))
unplugin-vue-macros:
specifier: ^2.14.5
version: 2.14.5(@vueuse/core@9.13.0(vue@3.5.18(typescript@5.9.2)))(esbuild@0.25.9)(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.2(@types/node@24.3.0)(jiti@2.5.1)(sass@1.90.0))(vue-tsc@3.0.5(typescript@5.9.2))(vue@3.5.18(typescript@5.9.2))
version: 2.14.5(@vueuse/core@14.0.0-alpha.0(vue@3.5.18(typescript@5.9.2)))(esbuild@0.25.9)(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.2(@types/node@24.3.0)(jiti@2.5.1)(sass@1.90.0))(vue-tsc@3.0.5(typescript@5.9.2))(vue@3.5.18(typescript@5.9.2))
vite:
specifier: ^7.0.3
version: 7.1.2(@types/node@24.3.0)(jiti@2.5.1)(sass@1.90.0)
@@ -590,25 +593,21 @@ packages:
resolution: {integrity: sha512-mMB1AvqzTH25rbUo1eRfvFzNqBopX6aRlDmO1fIVVzIWi6YJNKckxbkGaatez4hH/n86IR6aEdZFM3qBUjn3Tg==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@oxc-resolver/binding-linux-arm64-musl@4.2.0':
resolution: {integrity: sha512-9oPBU8Yb35z15/14LzALn/8rRwwrtfe19l25N1MRZVSONGiOwfzWNqDNjWiDdyW+EUt/hlylmFOItZmreL6iIw==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@oxc-resolver/binding-linux-x64-gnu@4.2.0':
resolution: {integrity: sha512-8wU4fwHb0b45i0qMBJ24UYBEtaLyvYWUOqVVCn0SpQZ1mhWWC8dvD6+zIVAKRVex/cKdgzi3imXoKGIDqVEu9w==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@oxc-resolver/binding-linux-x64-musl@4.2.0':
resolution: {integrity: sha512-5CS2wlGxzESPJCj4NlNGr73QCku75VpGtkwNp8qJF4hLELKAzkoqIB0eBbcvNPg8m2rB7YeXb1u+puGUKXDhNQ==}
cpu: [x64]
os: [linux]
libc: [musl]
'@oxc-resolver/binding-wasm32-wasi@4.2.0':
resolution: {integrity: sha512-VOLpvmVAQZjvj/7Et/gYzW6yBqL9VKjLWOGaFiQ7cvTpY9R9d/1mrNKEuP3beDHF2si2fM5f2pl9bL+N4tvwiA==}
@@ -654,42 +653,36 @@ packages:
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm-musl@2.5.1':
resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-arm64-glibc@2.5.1':
resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm64-musl@2.5.1':
resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-x64-glibc@2.5.1':
resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-x64-musl@2.5.1':
resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [musl]
'@parcel/watcher-win32-arm64@2.5.1':
resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
@@ -759,67 +752,56 @@ packages:
resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.46.2':
resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==}
cpu: [arm]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.46.2':
resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.46.2':
resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-loongarch64-gnu@4.46.2':
resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==}
cpu: [loong64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-ppc64-gnu@4.46.2':
resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.46.2':
resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.46.2':
resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==}
cpu: [riscv64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.46.2':
resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.46.2':
resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.46.2':
resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rollup/rollup-win32-arm64-msvc@4.46.2':
resolution: {integrity: sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==}
@@ -869,8 +851,8 @@ packages:
'@types/sax@1.2.7':
resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==}
'@types/web-bluetooth@0.0.16':
resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==}
'@types/web-bluetooth@0.0.21':
resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
'@unocss/astro@66.4.2':
resolution: {integrity: sha512-En3AKHwkiPxtZT95vkVrNiRYrB+DFVCikew6/dMMCWDWVKK0+5tEVUTzR1ak3+YnzAXl0NpWj8D4zHb0PxOs/A==}
@@ -1226,14 +1208,18 @@ packages:
'@vue/shared@3.5.18':
resolution: {integrity: sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==}
'@vueuse/core@9.13.0':
resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==}
'@vueuse/core@14.0.0-alpha.0':
resolution: {integrity: sha512-y2964MhoYalRdiBX+ilOOwh3EHsZyDhOb/hwZTkLlytcVrtX+Gbz+ffsAomaazJzZ7m/u+KI/5hLEdSHhjelgA==}
peerDependencies:
vue: ^3.5.0
'@vueuse/metadata@9.13.0':
resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==}
'@vueuse/metadata@14.0.0-alpha.0':
resolution: {integrity: sha512-FyQ7kAVMnccJwp0Wt2JuEjCNGl4lpOXKQEqzTbiqhKydQBK0urGaa+v12u8qJxf4XaaPNufLdoCQYQh8ya63JQ==}
'@vueuse/shared@9.13.0':
resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==}
'@vueuse/shared@14.0.0-alpha.0':
resolution: {integrity: sha512-J8cmTJkB0hAwPBXRR5U3N9FJkhPBrhyYiQm21kZ3j/o8W69Pg6JlPSxLOJtkg+AwC/r5x7Gpq2Vglv84vHotwA==}
peerDependencies:
vue: ^3.5.0
acorn@8.15.0:
resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
@@ -3688,17 +3674,6 @@ packages:
vscode-uri@3.1.0:
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
vue-demi@0.14.10:
resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
engines: {node: '>=12'}
hasBin: true
peerDependencies:
'@vue/composition-api': ^1.0.0-rc.1
vue: ^3.0.0-0 || ^2.6.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
vue-flow-layout@0.2.0:
resolution: {integrity: sha512-zKgsWWkXq0xrus7H4Mc+uFs1ESrmdTXlO0YNbR6wMdPaFvosL3fMB8N7uTV308UhGy9UvTrGhIY7mVz9eN+L0Q==}
@@ -4460,8 +4435,7 @@ snapshots:
dependencies:
'@types/node': 24.3.0
'@types/web-bluetooth@0.0.16':
optional: true
'@types/web-bluetooth@0.0.21': {}
'@unocss/astro@66.4.2(vite@7.1.2(@types/node@24.3.0)(jiti@2.5.1)(sass@1.90.0))':
dependencies:
@@ -4702,13 +4676,13 @@ snapshots:
unplugin: 1.16.1
vue: 3.5.18(typescript@5.9.2)
'@vue-macros/define-models@1.3.5(@vueuse/core@9.13.0(vue@3.5.18(typescript@5.9.2)))(vue@3.5.18(typescript@5.9.2))':
'@vue-macros/define-models@1.3.5(@vueuse/core@14.0.0-alpha.0(vue@3.5.18(typescript@5.9.2)))(vue@3.5.18(typescript@5.9.2))':
dependencies:
'@vue-macros/common': 1.16.1(vue@3.5.18(typescript@5.9.2))
ast-walker-scope: 0.6.2
unplugin: 1.16.1
optionalDependencies:
'@vueuse/core': 9.13.0(vue@3.5.18(typescript@5.9.2))
'@vueuse/core': 14.0.0-alpha.0(vue@3.5.18(typescript@5.9.2))
transitivePeerDependencies:
- vue
@@ -5013,27 +4987,18 @@ snapshots:
'@vue/shared@3.5.18': {}
'@vueuse/core@9.13.0(vue@3.5.18(typescript@5.9.2))':
'@vueuse/core@14.0.0-alpha.0(vue@3.5.18(typescript@5.9.2))':
dependencies:
'@types/web-bluetooth': 0.0.16
'@vueuse/metadata': 9.13.0
'@vueuse/shared': 9.13.0(vue@3.5.18(typescript@5.9.2))
vue-demi: 0.14.10(vue@3.5.18(typescript@5.9.2))
transitivePeerDependencies:
- '@vue/composition-api'
- vue
optional: true
'@types/web-bluetooth': 0.0.21
'@vueuse/metadata': 14.0.0-alpha.0
'@vueuse/shared': 14.0.0-alpha.0(vue@3.5.18(typescript@5.9.2))
vue: 3.5.18(typescript@5.9.2)
'@vueuse/metadata@9.13.0':
optional: true
'@vueuse/metadata@14.0.0-alpha.0': {}
'@vueuse/shared@9.13.0(vue@3.5.18(typescript@5.9.2))':
'@vueuse/shared@14.0.0-alpha.0(vue@3.5.18(typescript@5.9.2))':
dependencies:
vue-demi: 0.14.10(vue@3.5.18(typescript@5.9.2))
transitivePeerDependencies:
- '@vue/composition-api'
- vue
optional: true
vue: 3.5.18(typescript@5.9.2)
acorn@8.15.0: {}
@@ -7557,7 +7522,7 @@ snapshots:
transitivePeerDependencies:
- vue
unplugin-vue-macros@2.14.5(@vueuse/core@9.13.0(vue@3.5.18(typescript@5.9.2)))(esbuild@0.25.9)(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.2(@types/node@24.3.0)(jiti@2.5.1)(sass@1.90.0))(vue-tsc@3.0.5(typescript@5.9.2))(vue@3.5.18(typescript@5.9.2)):
unplugin-vue-macros@2.14.5(@vueuse/core@14.0.0-alpha.0(vue@3.5.18(typescript@5.9.2)))(esbuild@0.25.9)(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.2(@types/node@24.3.0)(jiti@2.5.1)(sass@1.90.0))(vue-tsc@3.0.5(typescript@5.9.2))(vue@3.5.18(typescript@5.9.2)):
dependencies:
'@vue-macros/better-define': 1.11.4(vue@3.5.18(typescript@5.9.2))
'@vue-macros/boolean-prop': 0.5.5(vue@3.5.18(typescript@5.9.2))
@@ -7565,7 +7530,7 @@ snapshots:
'@vue-macros/common': 1.16.1(vue@3.5.18(typescript@5.9.2))
'@vue-macros/config': 0.6.1(vue@3.5.18(typescript@5.9.2))
'@vue-macros/define-emit': 0.5.4(vue@3.5.18(typescript@5.9.2))
'@vue-macros/define-models': 1.3.5(@vueuse/core@9.13.0(vue@3.5.18(typescript@5.9.2)))(vue@3.5.18(typescript@5.9.2))
'@vue-macros/define-models': 1.3.5(@vueuse/core@14.0.0-alpha.0(vue@3.5.18(typescript@5.9.2)))(vue@3.5.18(typescript@5.9.2))
'@vue-macros/define-prop': 0.6.5(vue@3.5.18(typescript@5.9.2))
'@vue-macros/define-props': 4.0.6(@vue-macros/reactivity-transform@1.1.6(vue@3.5.18(typescript@5.9.2)))(vue@3.5.18(typescript@5.9.2))
'@vue-macros/define-props-refs': 1.3.5(vue@3.5.18(typescript@5.9.2))
@@ -7731,11 +7696,6 @@ snapshots:
vscode-uri@3.1.0: {}
vue-demi@0.14.10(vue@3.5.18(typescript@5.9.2)):
dependencies:
vue: 3.5.18(typescript@5.9.2)
optional: true
vue-flow-layout@0.2.0: {}
vue-observe-visibility@2.0.0-alpha.1(vue@3.5.18(typescript@5.9.2)):

View File

@@ -0,0 +1,54 @@
[
{
"id": "article_nce1",
"name": "新概念英语1-课文",
"description": "",
"category": "文章学习",
"tags": [
"新概念英语"
],
"url": "NCE_1.json",
"length": 72,
"translateLanguage": "common",
"language": "en"
},
{
"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": 60,
"translateLanguage": "common",
"language": "en"
},
{
"id": "article_nce4",
"name": "新概念英语4-课文",
"description": "新概念英语4-课文",
"category": "文章学习",
"tags": [
"新概念英语"
],
"url": "NCE_4.json",
"length": 48,
"translateLanguage": "common",
"language": "en"
}
]

View File

@@ -1,8 +1,8 @@
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 bookList = require('../public/list/book-list.json')
const dictList = require('../public/list/dict-list.json')
// 你的网站域名
const SITE_URL = 'https://2study.top'

View File

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

View File

@@ -4,13 +4,13 @@ import { BaseState, useBaseStore } from "@/stores/base.ts";
import { useRuntimeStore } from "@/stores/runtime.ts";
import { useSettingStore } from "@/stores/setting.ts";
import useTheme from "@/hooks/theme.ts";
import { APP_VERSION, LOCAL_FILE_KEY, SAVE_DICT_KEY, SAVE_SETTING_KEY } from "@/utils/const.ts";
import { shakeCommonDict } from "@/utils";
import { routes } from "@/router.ts";
import { get, set } from 'idb-keyval'
import { useRoute } from "vue-router";
import { DictId } from "@/types/types.ts";
import { APP_VERSION, LOCAL_FILE_KEY, SAVE_DICT_KEY, SAVE_SETTING_KEY } from "@/config/ENV.ts";
const store = useBaseStore()
const runtimeStore = useRuntimeStore()

5
src/apis/index.ts Normal file
View File

@@ -0,0 +1,5 @@
import http from "@/utils/http.ts";
export function officialList() {
return http('dict/officialList', null, null, 'get')
}

View File

@@ -1,56 +1,54 @@
[
[
{
"id": "article_nce1",
"name": "新概念英语1-课文",
"description": "",
"category": "文章学习",
"tags": [
"新概念英语"
],
"url": "NCE_1.json",
"length": 72,
"translateLanguage": "common",
"language": "en"
},
{
"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": 60,
"translateLanguage": "common",
"language": "en"
},
{
"id": "article_nce4",
"name": "新概念英语4-课文",
"description": "新概念英语4-课文",
"category": "文章学习",
"tags": [
"新概念英语"
],
"url": "NCE_4.json",
"length": 48,
"translateLanguage": "common",
"language": "en"
}
]
{
"id": "article_nce1",
"name": "新概念英语1-课文",
"description": "",
"category": "文章学习",
"tags": [
"新概念英语"
],
"url": "NCE_1.json",
"length": 72,
"translateLanguage": "common",
"language": "en"
},
{
"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": 60,
"translateLanguage": "common",
"language": "en"
},
{
"id": "article_nce4",
"name": "新概念英语4-课文",
"description": "新概念英语4-课文",
"category": "文章学习",
"tags": [
"新概念英语"
],
"url": "NCE_4.json",
"length": 48,
"translateLanguage": "common",
"language": "en"
}
]

View File

@@ -2,13 +2,58 @@ export const GITHUB = 'https://github.com/zyronon/TypeWords'
export const ProjectName = 'Type Words'
export const Host = '2study.top'
export const Origin = `https://${Host}`
export const APP_NAME = 'Type Words'
const common = {
word_dict_list_version: 1
}
const map = {
dev: {
api: 'http://localhost/index.php',
api: 'http://localhost/',
}
}
export const env = Object.assign(map['dev'], common)
export const DICT_LIST = {
WORD: {
ALL: '/list/dict-list.json',
RECOMMENDED: '/list/recommend-dict-list.json',
},
ARTICLE: {
ALL: '/list/book-list.json',
RECOMMENDED: '/list/book-list.json',
}
}
export const SoundFileOptions = [
{value: '机械键盘', label: '机械键盘'},
{value: '机械键盘1', label: '机械键盘1'},
{value: '机械键盘2', label: '机械键盘2'},
{value: '老式机械键盘', label: '老式机械键盘'},
{value: '笔记本键盘', label: '笔记本键盘'},
]
export const APP_VERSION = {
key: 'type-words-app-version',
version: 1
}
export const SAVE_DICT_KEY = {
key: 'typing-word-dict',
version: 4
}
export const SAVE_SETTING_KEY = {
key: 'typing-word-setting',
version: 15
}
export const EXPORT_DATA_KEY = {
key: 'typing-word-export',
version: 4
}
export const LOCAL_FILE_KEY = 'typing-word-files'
export const PracticeSaveWordKey = {
key: 'PracticeSaveWord',
version: 1
}
export const PracticeSaveArticleKey = {
key: 'PracticeSaveArticle',
version: 1
}

View File

@@ -1,5 +1,6 @@
// src/directives/loading.js
import {createApp, h} from 'vue'
//@ts-ignore
import IconEosIconsLoading from '~icons/eos-icons/loading'
// 创建一个 Loading 组件

View File

@@ -1,7 +1,8 @@
import {onMounted, watchEffect} from "vue"
import {useSettingStore} from "@/stores/setting.ts";
import {PronunciationApi} from "@/types/types.ts";
import {SoundFileOptions} from "@/utils/const.ts";
import { SoundFileOptions } from "@/config/ENV.ts";
export function useSound(audioSrcList?: string[], audioFileLength?: number) {
let audioList: HTMLAudioElement[] = $ref([])

View File

@@ -14,11 +14,11 @@ import PopConfirm from "@/components/PopConfirm.vue";
import { watch } from "vue";
import { getDefaultDict } from "@/types/func.ts";
import DeleteIcon from "@/components/icon/DeleteIcon.vue";
import recommendBookList from "@/assets/book-list.json";
import dayjs from "dayjs";
import isBetween from "dayjs/plugin/isBetween";
import { PracticeSaveArticleKey } from "@/utils/const.ts";
import isoWeek from 'dayjs/plugin/isoWeek'
import { useFetch } from "@vueuse/core";
import { DICT_LIST, PracticeSaveArticleKey } from "@/config/ENV.ts";
dayjs.extend(isoWeek)
dayjs.extend(isBetween);
@@ -152,6 +152,9 @@ const weekList = $computed(() => {
});
return list
})
const {data: recommendBookList, isFetching} = useFetch(DICT_LIST.ARTICLE.RECOMMENDED).json()
</script>
<template>
@@ -246,7 +249,8 @@ const weekList = $computed(() => {
</div>
</div>
<div class="card flex flex-col">
<div class="card flex flex-col min-h-50" v-loading="isFetching">
<div class="flex justify-between">
<div class="title">推荐</div>
<div class="flex gap-4 items-center">
@@ -258,7 +262,7 @@ const weekList = $computed(() => {
<Book :is-add="false"
quantifier=""
:item="item as any"
v-for="(item, j) in recommendBookList[0]" @click="goBookDetail(item as any)"/>
v-for="(item, j) in recommendBookList" @click="goBookDetail(item as any)"/>
</div>
</div>
</BasePage>

View File

@@ -11,15 +11,16 @@ import BaseButton from "@/components/BaseButton.vue";
import { useRoute, useRouter } from "vue-router";
import EditBook from "@/pages/article/components/EditBook.vue";
import { computed, onMounted } from "vue";
import { _dateFormat, _getDictDataByUrl, cloneDeep, msToHourMinute, total, useNav } from "@/utils";
import { _dateFormat, _getDictDataByUrl, msToHourMinute, total, useNav } from "@/utils";
import BaseIcon from "@/components/BaseIcon.vue";
import { useArticleOptions } from "@/hooks/dict.ts";
import { getDefaultArticle, getDefaultDict } from "@/types/func.ts";
import Toast from "@/components/base/toast/Toast.ts";
import ArticleAudio from "@/pages/article/components/ArticleAudio.vue";
import { MessageBox } from "@/utils/MessageBox.tsx";
import book_list from "@/assets/book-list.json";
import { useSettingStore } from "@/stores/setting.ts";
import { useFetch } from "@vueuse/core";
import { DICT_LIST } from "@/config/ENV.ts";
const runtimeStore = useRuntimeStore()
const settingStore = useSettingStore()
@@ -109,12 +110,14 @@ const {
toggleArticleCollect
} = useArticleOptions()
const {data: book_list} = useFetch(DICT_LIST.ARTICLE.ALL).json()
function reset() {
MessageBox.confirm(
'继续此操作会重置所有文章,并从官方书籍获取最新文章列表,学习记录不会被重置。确认恢复默认吗?',
'恢复默认',
async () => {
let dict = book_list.flat().find(v => v.url === runtimeStore.editDict.url) as Dict
let dict = book_list.value.find(v => v.url === runtimeStore.editDict.url) as Dict
if (dict && dict.id) {
dict = await _getDictDataByUrl(dict, DictType.article)
let rIndex = base.article.bookList.findIndex(v => v.id === runtimeStore.editDict.id)

View File

@@ -1,18 +1,19 @@
<script setup lang="ts">
import {useNav} from "@/utils";
import { useNav } from "@/utils";
import BasePage from "@/components/BasePage.vue";
import {DictResource} from "@/types/types.ts";
import {useRuntimeStore} from "@/stores/runtime.ts";
import { DictResource } from "@/types/types.ts";
import { useRuntimeStore } from "@/stores/runtime.ts";
import BaseIcon from "@/components/BaseIcon.vue";
import Empty from "@/components/Empty.vue";
import Input from "@/components/Input.vue";
import BaseButton from "@/components/BaseButton.vue";
import DictList from "@/components/list/DictList.vue";
import BackIcon from "@/components/BackIcon.vue";
import {useRouter} from "vue-router";
import book_list from "@/assets/book-list.json";
import {computed} from "vue";
import {getDefaultDict} from "@/types/func.ts";
import { useRouter } from "vue-router";
import { computed } from "vue";
import { getDefaultDict } from "@/types/func.ts";
import { useFetch } from "@vueuse/core";
import { DICT_LIST } from "@/config/ENV.ts";
const {nav} = useNav()
const runtimeStore = useRuntimeStore()
@@ -30,11 +31,12 @@ async function getDictDetail(val: DictResource) {
let showSearchInput = $ref(false)
let searchKey = $ref('')
const {data: bookList, isFetching} = useFetch(DICT_LIST.ARTICLE.ALL).json()
const searchList = computed<any[]>(() => {
if (searchKey) {
let s = searchKey.toLowerCase()
return book_list.flat().filter((item) => {
return bookList.value.filter((item) => {
return item.id.toLowerCase().includes(s)
|| item.name.toLowerCase().includes(s)
|| item.category.toLowerCase().includes(s)
@@ -49,7 +51,7 @@ const searchList = computed<any[]>(() => {
<template>
<BasePage>
<div class="card">
<div class="card min-h-50" v-loading="isFetching">
<div class="flex items-center relative gap-2">
<BackIcon class="z-2" @Click='router.back'/>
<div class="flex flex-1 gap-4" v-if="showSearchInput">
@@ -75,9 +77,9 @@ const searchList = computed<any[]>(() => {
</div>
<div class="w-full mt-2" v-else>
<DictList
v-if="book_list.flat().length "
v-if="bookList?.length "
@selectDict="selectDict"
:list="book_list.flat()"
:list="bookList"
quantifier="篇"
:select-id="'-1'"/>
</div>

View File

@@ -31,11 +31,10 @@ import EditSingleArticleModal from "@/pages/article/components/EditSingleArticle
import Tooltip from "@/components/base/Tooltip.vue";
import ConflictNotice from "@/components/ConflictNotice.vue";
import { useRoute, useRouter } from "vue-router";
import book_list from "@/assets/book-list.json";
import PracticeLayout from "@/components/PracticeLayout.vue";
import ArticleAudio from "@/pages/article/components/ArticleAudio.vue";
import { PracticeSaveArticleKey } from "@/utils/const.ts";
import VolumeSetting from "@/pages/article/components/VolumeSetting.vue";
import { DICT_LIST, PracticeSaveArticleKey } from "@/config/ENV.ts";
const store = useBaseStore()
const settingStore = useSettingStore()
@@ -51,7 +50,6 @@ let typingArticleRef = $ref<any>()
let loading = $ref<boolean>(false)
let allWrongWords = new Set()
let editArticle = $ref<Article>(getDefaultArticle())
let speedMinute = $ref(0)
let timer = $ref(0)
let isFocus = true
@@ -109,6 +107,8 @@ async function init() {
if (dictId) {
//先在自己的词典列表里面找,如果没有再在资源列表里面找
dict = store.article.bookList.find(v => v.id === dictId)
let r = await fetch(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.id) {
//如果是不是自定义词典,就请求数据

View File

@@ -1,9 +1,9 @@
<script setup lang="ts">
import { Article } from "@/types/types.ts";
import { watch } from "vue";
import { LOCAL_FILE_KEY } from "@/utils/const.ts";
import { get } from "idb-keyval";
import Audio from "@/components/base/Audio.vue";
import { LOCAL_FILE_KEY } from "@/config/ENV.ts";
const props = defineProps<{
article: Article

View File

@@ -18,10 +18,10 @@ import Tooltip from "@/components/base/Tooltip.vue";
import InputNumber from "@/components/base/InputNumber.vue";
import {nanoid} from "nanoid";
import {update} from "idb-keyval";
import {LOCAL_FILE_KEY} from "@/utils/const.ts";
import ArticleAudio from "@/pages/article/components/ArticleAudio.vue";
import BaseInput from "@/components/base/BaseInput.vue";
import Textarea from "@/components/base/Textarea.vue";
import { LOCAL_FILE_KEY } from "@/config/ENV.ts";
const Dialog = defineAsyncComponent(() => import('@/components/dialog/Dialog.vue'))

View File

@@ -18,8 +18,8 @@ import Space from "@/pages/article/components/Space.vue";
import { useWordOptions } from "@/hooks/dict.ts";
import nlp from "compromise/three";
import { nanoid } from "nanoid";
import { PracticeSaveArticleKey } from "@/utils/const.ts";
import { usePracticeStore } from "@/stores/practice.ts";
import { PracticeSaveArticleKey } from "@/config/ENV.ts";
interface IProps {
article: Article,

View File

@@ -38,7 +38,3 @@ useWindowClick(() => show = false)
</MiniDialog>
</div>
</template>
<style scoped lang="scss">
@import "@/assets/css/style";
</style>

View File

@@ -6,20 +6,17 @@ import { getShortcutKey, useEventListener } from "@/hooks/event.ts";
import { checkAndUpgradeSaveDict, checkAndUpgradeSaveSetting, cloneDeep, loadJsLib, shakeCommonDict } from "@/utils";
import { DefaultShortcutKeyMap, ShortcutKey } from "@/types/types.ts";
import BaseButton from "@/components/BaseButton.vue";
import {
APP_NAME,
APP_VERSION,
EXPORT_DATA_KEY,
LOCAL_FILE_KEY, PracticeSaveArticleKey,
PracticeSaveWordKey,
SAVE_DICT_KEY,
SAVE_SETTING_KEY,
SoundFileOptions
} from "@/utils/const.ts";
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
import { useBaseStore } from "@/stores/base.ts";
import { saveAs } from "file-saver";
import { Origin } from "@/config/ENV.ts";
import {
APP_NAME, APP_VERSION,
EXPORT_DATA_KEY,
LOCAL_FILE_KEY,
Origin,
PracticeSaveArticleKey,
PracticeSaveWordKey, SAVE_DICT_KEY, SAVE_SETTING_KEY, SoundFileOptions
} from "@/config/ENV.ts";
import dayjs from "dayjs";
import BasePage from "@/components/BasePage.vue";
import Toast from '@/components/base/toast/Toast.ts'

View File

@@ -2,9 +2,9 @@
// import origin from './data.json'
import BaseButton from "@/components/BaseButton.vue";
import {checkAndUpgradeSaveDict} from "@/utils";
import {SAVE_DICT_KEY} from "@/utils/const.ts";
import str from './data.json'
import {get} from 'idb-keyval'
import { SAVE_DICT_KEY } from "@/config/ENV.ts";
let data = {}
let origin = {}

View File

@@ -1,8 +1,8 @@
<script setup lang="ts">
import {groupBy, useNav} from "@/utils";
import { groupBy, useNav } from "@/utils";
import BasePage from "@/components/BasePage.vue";
import {DictResource} from "@/types/types.ts";
import {useRuntimeStore} from "@/stores/runtime.ts";
import { DictResource } from "@/types/types.ts";
import { useRuntimeStore } from "@/stores/runtime.ts";
import BaseIcon from "@/components/BaseIcon.vue";
import Empty from "@/components/Empty.vue";
import Input from "@/components/Input.vue";
@@ -10,11 +10,12 @@ import BaseButton from "@/components/BaseButton.vue";
import DictList from "@/components/list/DictList.vue";
import BackIcon from "@/components/BackIcon.vue";
import DictGroup from "@/components/list/DictGroup.vue";
import {useBaseStore} from "@/stores/base.ts";
import {useRouter} from "vue-router";
import {computed} from "vue";
import {getDefaultDict} from "@/types/func.ts";
import dict_list from "@/assets/dict-list.json";
import { useBaseStore } from "@/stores/base.ts";
import { useRouter } from "vue-router";
import { computed } from "vue";
import { getDefaultDict } from "@/types/func.ts";
import { useFetch } from "@vueuse/core";
import { DICT_LIST } from "@/config/ENV.ts";
const {nav} = useNav()
const runtimeStore = useRuntimeStore()
@@ -45,9 +46,12 @@ function groupByDictTags(dictList: DictResource[]) {
}, {})
}
const {data: dict_list, isFetching} = useFetch(DICT_LIST.WORD.ALL).json()
const groupedByCategoryAndTag = $computed(() => {
const groupByCategory = groupBy(dict_list.flat(), 'category')
let data = []
if (!dict_list.value) return data
const groupByCategory = groupBy(dict_list.value.flat(), 'category')
for (const [key, value] of Object.entries(groupByCategory)) {
data.push([key, groupByDictTags(value)])
}
@@ -61,7 +65,7 @@ let searchKey = $ref('')
const searchList = computed<any[]>(() => {
if (searchKey) {
let s = searchKey.toLowerCase()
return dict_list.flat().filter((item) => {
return dict_list.value.flat().filter((item) => {
return item.id.toLowerCase().includes(s)
|| item.name.toLowerCase().includes(s)
|| item.category.toLowerCase().includes(s)
@@ -76,7 +80,7 @@ const searchList = computed<any[]>(() => {
<template>
<BasePage>
<div class="card">
<div class="card min-h-200" v-loading="isFetching">
<div class="flex items-center relative gap-2">
<BackIcon class="z-2" @click='router.back'/>
<div class="flex flex-1 gap-4" v-if="showSearchInput">
@@ -85,9 +89,11 @@ const searchList = computed<any[]>(() => {
</div>
<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"
icon="fluent:search-24-regular">
<BaseIcon
title="搜索"
@click="showSearchInput = true"
class="z-1"
icon="fluent:search-24-regular">
<IconFluentSearch24Regular/>
</BaseIcon>
</div>

View File

@@ -24,9 +24,9 @@ import { usePracticeStore } from "@/stores/practice.ts";
import Toast from '@/components/base/toast/Toast.ts'
import { getDefaultDict, getDefaultWord } from "@/types/func.ts";
import ConflictNotice from "@/components/ConflictNotice.vue";
import dict_list from "@/assets/dict-list.json";
import PracticeLayout from "@/components/PracticeLayout.vue";
import { PracticeSaveWordKey } from "@/utils/const.ts";
import { DICT_LIST, PracticeSaveWordKey } from "@/config/ENV.ts";
const {
isWordCollect,
@@ -64,6 +64,8 @@ async function loadDict() {
if (dictId) {
//先在自己的词典列表里面找,如果没有再在资源列表里面找
dict = store.word.bookList.find(v => v.id === dictId)
let r = await fetch(DICT_LIST.WORD.ALL)
let dict_list = await r.json()
if (!dict) dict = dict_list.flat().find(v => v.id === dictId) as Dict
if (dict && dict.id) {
//如果是不是自定义词典,就请求数据

View File

@@ -18,9 +18,9 @@ import DeleteIcon from "@/components/icon/DeleteIcon.vue";
import PracticeSettingDialog from "@/pages/word/components/PracticeSettingDialog.vue";
import ChangeLastPracticeIndexDialog from "@/pages/word/components/ChangeLastPracticeIndexDialog.vue";
import { useSettingStore } from "@/stores/setting.ts";
import recommendDictList from "@/assets/recommend-dict-list.json";
import CollectNotice from "@/components/CollectNotice.vue";
import { PracticeSaveWordKey } from "@/utils/const.ts";
import { useFetch } from "@vueuse/core";
import { DICT_LIST, PracticeSaveWordKey } from "@/config/ENV.ts";
const store = useBaseStore()
@@ -130,7 +130,6 @@ const progressTextRight = $computed(() => {
return store.sdict?.lastLearnIndex
})
function check(cb: Function) {
if (!store.sdict.id) {
Toast.warning('请先选择一本词典')
@@ -154,6 +153,8 @@ function saveLastPracticeIndex(e) {
localStorage.removeItem(PracticeSaveWordKey.key)
currentStudy = getCurrentStudyWord()
}
const {data: recommendDictList, isFetching} = useFetch(DICT_LIST.WORD.RECOMMENDED).json()
</script>
<template>
@@ -266,7 +267,7 @@ function saveLastPracticeIndex(e) {
</div>
</div>
<div class="card flex flex-col">
<div class="card flex flex-col overflow-hidden" v-loading="isFetching">
<div class="flex justify-between">
<div class="title">推荐</div>
<div class="flex gap-4 items-center">
@@ -274,7 +275,7 @@ function saveLastPracticeIndex(e) {
</div>
</div>
<div class="flex gap-4 flex-wrap mt-4">
<div class="flex gap-4 flex-wrap mt-4 min-h-50">
<Book :is-add="false"
quantifier="个词"
:item="item as any"

View File

@@ -1,10 +1,10 @@
import {defineStore} from 'pinia'
import {Dict, DictId, Word} from "../types/types.ts"
import {_getAccomplishDate, _getStudyProgress, checkAndUpgradeSaveDict} from "@/utils";
import {SAVE_DICT_KEY} from "@/utils/const.ts";
import {shallowReactive} from "vue";
import {getDefaultDict} from "@/types/func.ts";
import {get, set} from 'idb-keyval'
import { SAVE_DICT_KEY } from "@/config/ENV.ts";
export interface BaseState {
simpleWords: string[],

View File

@@ -1,8 +1,8 @@
import {defineStore} from "pinia"
import {checkAndUpgradeSaveSetting, cloneDeep} from "@/utils";
import {DefaultShortcutKeyMap} from "@/types/types.ts";
import {APP_VERSION, SAVE_SETTING_KEY} from "@/utils/const.ts";
import {get} from "idb-keyval";
import { APP_VERSION, SAVE_SETTING_KEY } from "@/config/ENV.ts";
export interface SettingState {
soundType: string,

View File

@@ -1,38 +0,0 @@
export const SoundFileOptions = [
{value: '机械键盘', label: '机械键盘'},
{value: '机械键盘1', label: '机械键盘1'},
{value: '机械键盘2', label: '机械键盘2'},
{value: '老式机械键盘', label: '老式机械键盘'},
{value: '笔记本键盘', label: '笔记本键盘'},
]
export const APP_NAME = 'Type Words'
export const APP_VERSION = {
key: 'type-words-app-version',
version: 1
}
export const SAVE_DICT_KEY = {
key: 'typing-word-dict',
version: 4
}
export const SAVE_SETTING_KEY = {
key: 'typing-word-setting',
version: 15
}
export const EXPORT_DATA_KEY = {
key: 'typing-word-export',
version: 4
}
export const LOCAL_FILE_KEY = 'typing-word-files'
export const PracticeSaveWordKey = {
key: 'PracticeSaveWord',
version: 1
}
export const PracticeSaveArticleKey = {
key: 'PracticeSaveArticle',
version: 1
}

View File

@@ -1,4 +1,3 @@
import {SAVE_SETTING_KEY} from "@/utils/const";
export default {
$notice(val) {

View File

@@ -1,114 +1,89 @@
// import axios, {AxiosInstance} from 'axios'
// // import globalMethods from './global-methods'
// // import Config from '../config/index'
// // import CONSTANT from './const_var'
// // import store from '../store'
// // import Storage from './storage'
//
// export const axiosInstance: AxiosInstance = axios.create({
// // baseURL: process.env.NODE_ENV === 'production' ? Config.PRODUCT_API_URL : Config.API_URL,
// // baseURL: 'http://testtestgp.com',
// timeout: 15000,
// })
//
// // request 拦截器
// axiosInstance.interceptors.request.use(
// (config) => {
// // console.log('config', config)
// if (config.url === 'https://api.fanyi.baidu.com/api/trans/vip/translate') {
// config.url = '/baidu'
// }
// return config
// },
// error => Promise.reject(error),
// )
import axios, { AxiosInstance } from 'axios'
import { env } from "@/config/ENV.ts";
import Toast from "@/components/base/toast/Toast.ts";
// respone 拦截器
// instance.interceptors.response.use(
// // 响应正常的处理
// (response) => {
// // console.log(response)
// // console.log(response.data)
// const { data } = response
// if (response.status !== 200) {
// globalMethods.$warning(response.statusText)
// return Promise.reject(data)
// }
// if (data === null) {
// return Promise.resolve({
// code: '009900',
// msg: '系统出现错误',
// data: {},
// })
// }
// return Promise.resolve(data)
// },
// // 请求出错的处理
// (error) => {
// console.log(error)
// if (error.response === undefined && error.status === undefined) {
// return Promise.resolve({
// code: '009900',
// msg: '服务器响应超时',
// data: null,
// })
// }
// if (error.response.status >= 500) {
// return Promise.resolve({
// code: '009900',
// msg: '服务器出现错误',
// data: null,
// })
// }
// if (error.response.status === 401) {
// return Promise.resolve({
// code: '009900',
// msg: '用户名或密码不正确',
// data: null,
// })
// }
// const { data } = error.response
// if (data.code !== undefined) {
// return Promise.resolve({
// code: data.code,
// msg: data.msg,
// })
// }
// return Promise.resolve({
// code: '009900',
// msg: data.msg,
// data: null,
// })
// },
// )
export const axiosInstance: AxiosInstance = axios.create({
baseURL: env.api,
timeout: 15000,
})
axiosInstance.interceptors.request.use(
(config) => {
// console.log('config', config)
// if (config.url === 'https://api.fanyi.baidu.com/api/trans/vip/translate') {
// config.url = '/baidu'
// }
return config
},
error => Promise.reject(error),
)
axiosInstance.interceptors.response.use(
// 响应正常的处理
(response) => {
// console.log(response)
// console.log(response.data)
const {data} = response
if (response.status !== 200) {
Toast.warning(response.statusText)
return Promise.reject(data)
}
if (data === null) {
return Promise.resolve({
code: '009900',
msg: '系统出现错误',
data: {},
})
}
return Promise.resolve(data)
},
// 请求出错的处理
(error) => {
console.log(error)
if (error.response === undefined && error.status === undefined) {
return Promise.resolve({
code: '009900',
msg: '服务器响应超时',
data: null,
})
}
if (error.response.status >= 500) {
return Promise.resolve({
code: '009900',
msg: '服务器出现错误',
data: null,
})
}
if (error.response.status === 401) {
return Promise.resolve({
code: '009900',
msg: '用户名或密码不正确',
data: null,
})
}
const {data} = error.response
if (data.code !== undefined) {
return Promise.resolve({
code: data.code,
msg: data.msg,
})
}
return Promise.resolve({
code: '009900',
msg: data.msg,
data: null,
})
},
)
/**
* @apiDescription 封装的网络请求方法
* @apiGroup
* @apiName request
* @apiParam url 地址
* @apiParam data 请求数据
* @apiParam params 请求参数
* @apiParam method 方法类型get或者post
* @apiParam version 接口版本号
* @apiParamExample
* request('Appointment/appointmentList', data, params, CONSTANT.GET)
* @apiReturn Promise
*/
// async function request(url, data = {}, params = {}, method = CONSTANT.POST, version = Config.API_VERSION) {
// // console.log(url)
// if (method === CONSTANT.POST) {
// data.userId = store.state.user.userInfo === null ? '' : store.state.user.userInfo.id
// } else {
// params.userId = store.state.user.userInfo === null ? '' : store.state.user.userInfo.id
// }
// return instance({
// url: version + url,
// method,
// data,
// params,
// })
// }
async function request(url, data = {}, params = {}, method) {
return axiosInstance({
url: '/v1/' + url,
method,
data,
params,
})
}
// export default request
export default request

View File

@@ -1,4 +1,4 @@
import { SAVE_DICT_KEY, SAVE_SETTING_KEY } from "@/utils/const.ts";
import { BaseState, DefaultBaseState } from "@/stores/base.ts";
import { getDefaultSettingState, SettingState } from "@/stores/setting.ts";
import { Dict, DictId, DictResource, DictType } from "@/types/types.ts";
@@ -6,13 +6,10 @@ import { useRouter } from "vue-router";
import { useRuntimeStore } from "@/stores/runtime.ts";
import dayjs from 'dayjs'
import axios from "axios";
import { env } from "@/config/ENV.ts";
import { env, SAVE_DICT_KEY, SAVE_SETTING_KEY } from "@/config/ENV.ts";
import { nextTick } from "vue";
import Toast from '@/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";
import { getDefaultDict, getDefaultWord } from "@/types/func.ts";
import duration from "dayjs/plugin/duration";
dayjs.extend(duration);
@@ -58,141 +55,6 @@ export function checkAndUpgradeSaveDict(val: any) {
})
return defaultState
} else {
if (version === 3) {
localStorage.setItem('type-word-dict-v3', JSON.stringify(state))
set('type-word-dict-v3', JSON.stringify(state))
let studyDictId = ''
if (state.current.index >= 0) {
let dict = state.myDictList[state.current.index]
if (dict) {
studyDictId = dict.id
}
}
const safeString = (str) => (typeof str === 'string' ? str.trim() : '');
function formatWord(dict) {
dict.words = dict.words?.map?.(v => {
return getDefaultWord({
word: v.name,
phonetic0: v.usphone,
phonetic1: v.ukphone,
trans: v.trans.map(line => {
const match = line.match(/^([^\s.]+\.?)\s*(.*)$/);
if (match) {
let pos = safeString(match[1]);
let cn = safeString(match[2]);
// 如果 pos 不是常规词性(不以字母开头),例如 "【名】"
if (!/^[a-zA-Z]+\.?$/.test(pos)) {
cn = safeString(line); // 整行放到 cn
pos = ''; // pos 置空
}
return {pos, cn};
}
return {pos: '', cn: safeString(line)};
})
})
}) || []
dict.statistics = dict.statistics?.map?.(v => {
return {
startDate: v.startDate,
spend: v.endDate - v.startDate,
total: v.total,
new: v.total,
wrong: v.wrongWordNumber
}
}) || []
dict.articles = dict.articles?.map?.(v => {
let r = getDefaultArticle({
textTranslate: v.textCustomTranslate
})
checkRiskKey(r, v)
return r
}) || []
}
state.myDictList.map((v: any) => {
try {
let currentDictId = v.id
let currentType = v.type
delete v.type
if (['collect', 'simple', 'wrong'].includes(currentType)) {
formatWord(v)
delete v.id
delete v.name
if (currentType === 'collect') {
if (v.words.length) {
if (currentDictId === studyDictId) defaultState.word.studyIndex = 0
checkRiskKey(defaultState.word.bookList[0], cloneDeep(v))
defaultState.word.bookList[0].length = v.words.length
}
if (v.articles.length) {
if (currentDictId === studyDictId) defaultState.article.studyIndex = 0
checkRiskKey(defaultState.article.bookList[0], cloneDeep(v))
defaultState.article.bookList[0].length = v.articles.length
}
}
if (currentType === 'simple' || currentType === 'skip') {
if (currentDictId === studyDictId) defaultState.word.studyIndex = 2
checkRiskKey(defaultState.word.bookList[2], v)
defaultState.word.bookList[2].length = v.words.length
}
if (currentType === 'wrong') {
if (currentDictId === studyDictId) defaultState.word.studyIndex = 1
checkRiskKey(defaultState.word.bookList[1], v)
defaultState.word.bookList[1].length = v.words.length
}
}
if (currentType === 'word') {
if (v.isCustom) {
formatWord(v)
let dict = getDefaultDict({custom: true})
checkRiskKey(dict, v)
dict.length = dict.words.length
defaultState.word.bookList.push(dict)
if (currentDictId === studyDictId) defaultState.word.studyIndex = defaultState.word.bookList.length - 1
} else {
//当时把选中的词典的id设为随机了导致通过id找不到
let r: any = dict_list.flat().find(a => a.name === v.name)
if (r) {
formatWord(v)
let dict = getDefaultDict(r)
checkRiskKey(dict, v)
dict.id = r.id
defaultState.word.bookList.push(dict)
if (currentDictId === studyDictId) defaultState.word.studyIndex = defaultState.word.bookList.length - 1
}
}
}
if (currentType === 'article') {
if (v.isCustom) {
formatWord(v)
let dict = getDefaultDict({custom: true})
checkRiskKey(dict, v)
dict.length = dict.articles.length
defaultState.article.bookList.push(dict)
if (currentDictId === studyDictId) defaultState.article.studyIndex = defaultState.article.bookList.length - 1
} else {
//当时把选中的词典的id设为随机了
let r: any = book_list.flat().find(a => a.name === v.name)
if (r) {
formatWord(v)
let dict = getDefaultDict(r)
checkRiskKey(dict, v)
dict.id = r.id
defaultState.article.bookList.push(dict)
if (currentDictId === studyDictId) defaultState.article.studyIndex = defaultState.article.bookList.length - 1
}
}
}
} catch (e) {
console.error('升级数据失败!', e)
}
})
}
checkRiskKey(defaultState, state)
return defaultState
}
@@ -264,11 +126,8 @@ export function shakeCommonDict(n: BaseState): BaseState {
export function isMobile(): boolean {
// return /Mobi|Android|iPhone/i.test(navigator.userAgent)
return (
'ontouchstart' in window ||
navigator.maxTouchPoints > 0 ||
navigator.msMaxTouchPoints > 0
);
//@ts-ignore
return ('ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0);
}
export async function getDictFile(url: string) {