feat:移除无用依赖
This commit is contained in:
10
auto-imports.d.ts
vendored
10
auto-imports.d.ts
vendored
@@ -1,10 +0,0 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
// Generated by unplugin-auto-import
|
||||
export {}
|
||||
declare global {
|
||||
const ElMessage: typeof import('element-plus/es')['ElMessage']
|
||||
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
|
||||
}
|
||||
43
components.d.ts
vendored
43
components.d.ts
vendored
@@ -1,43 +0,0 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
// Generated by unplugin-vue-components
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
export {}
|
||||
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
BackIcon: typeof import('./src/components/icon/BackIcon.vue')['default']
|
||||
BaseButton: typeof import('./src/components/BaseButton.vue')['default']
|
||||
BaseIcon: typeof import('./src/components/BaseIcon.vue')['default']
|
||||
Close: typeof import('./src/components/icon/Close.vue')['default']
|
||||
DeleteIcon: typeof import('./src/components/icon/DeleteIcon.vue')['default']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
ElForm: typeof import('element-plus/es')['ElForm']
|
||||
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||
ElProgress: typeof import('element-plus/es')['ElProgress']
|
||||
ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
|
||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
ElSlider: typeof import('element-plus/es')['ElSlider']
|
||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||
ElTableV2: typeof import('element-plus/es')['ElTableV2']
|
||||
ElUpload: typeof import('element-plus/es')['ElUpload']
|
||||
Empty: typeof import('./src/components/Empty.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
SlideHorizontal: typeof import('./src/components/slide/SlideHorizontal.vue')['default']
|
||||
SlideItem: typeof import('./src/components/slide/SlideItem.vue')['default']
|
||||
VolumeIcon: typeof import('./src/components/icon/VolumeIcon.vue')['default']
|
||||
}
|
||||
export interface ComponentCustomProperties {
|
||||
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
|
||||
}
|
||||
}
|
||||
@@ -26,16 +26,15 @@
|
||||
"git-last-commit": "^1.0.1",
|
||||
"libarchive-wasm": "^1.2.0",
|
||||
"localforage": "^1.10.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mitt": "^3.0.1",
|
||||
"nanoid": "^5.1.5",
|
||||
"pinia": "^3.0.3",
|
||||
"sentence-splitter": "^4.4.1",
|
||||
"string-comparison": "^1.3.0",
|
||||
"tesseract.js": "^4.1.4",
|
||||
"unplugin-element-plus": "^0.10.0",
|
||||
"vue": "^3.5.17",
|
||||
"vue-activity-calendar": "^1.2.2",
|
||||
"vue-i18n": "^9.14.4",
|
||||
"vue-router": "^4.5.1",
|
||||
"vue-virtual-scroller": "2.0.0-beta.8"
|
||||
},
|
||||
@@ -57,8 +56,6 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.8.3",
|
||||
"unocss": "^66.4.0",
|
||||
"unplugin-auto-import": "^0.16.7",
|
||||
"unplugin-vue-components": "^0.25.2",
|
||||
"unplugin-vue-macros": "^2.14.5",
|
||||
"vite": "^7.0.3",
|
||||
"vite-plugin-cdn-import": "^1.0.1",
|
||||
|
||||
241
pnpm-lock.yaml
generated
241
pnpm-lock.yaml
generated
@@ -44,9 +44,6 @@ importers:
|
||||
localforage:
|
||||
specifier: ^1.10.0
|
||||
version: 1.10.0
|
||||
lodash-es:
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
mitt:
|
||||
specifier: ^3.0.1
|
||||
version: 3.0.1
|
||||
@@ -65,15 +62,15 @@ importers:
|
||||
tesseract.js:
|
||||
specifier: ^4.1.4
|
||||
version: 4.1.4
|
||||
unplugin-element-plus:
|
||||
specifier: ^0.10.0
|
||||
version: 0.10.0
|
||||
vue:
|
||||
specifier: ^3.5.17
|
||||
version: 3.5.17(typescript@5.8.3)
|
||||
vue-activity-calendar:
|
||||
specifier: ^1.2.2
|
||||
version: 1.2.2
|
||||
vue-i18n:
|
||||
specifier: ^9.14.4
|
||||
version: 9.14.4(vue@3.5.17(typescript@5.8.3))
|
||||
vue-router:
|
||||
specifier: ^4.5.1
|
||||
version: 4.5.1(vue@3.5.17(typescript@5.8.3))
|
||||
@@ -108,9 +105,6 @@ importers:
|
||||
cz-conventional-changelog:
|
||||
specifier: ^3.3.0
|
||||
version: 3.3.0(@types/node@24.0.11)(typescript@5.8.3)
|
||||
daisyui:
|
||||
specifier: ^5.0.50
|
||||
version: 5.0.50
|
||||
esm:
|
||||
specifier: ^3.2.25
|
||||
version: 3.2.25
|
||||
@@ -136,11 +130,11 @@ importers:
|
||||
specifier: ^66.4.0
|
||||
version: 66.4.0(postcss@8.5.6)(vite@7.0.3(@types/node@24.0.11)(jiti@2.4.2)(sass@1.89.2))
|
||||
unplugin-auto-import:
|
||||
specifier: ^0.16.7
|
||||
version: 0.16.7(@vueuse/core@9.13.0(vue@3.5.17(typescript@5.8.3)))(rollup@4.44.2)
|
||||
specifier: '^19.3.0 '
|
||||
version: 19.3.0(@vueuse/core@9.13.0(vue@3.5.17(typescript@5.8.3)))
|
||||
unplugin-vue-components:
|
||||
specifier: ^0.25.2
|
||||
version: 0.25.2(@babel/parser@7.28.0)(rollup@4.44.2)(vue@3.5.17(typescript@5.8.3))
|
||||
specifier: ^28.8.0
|
||||
version: 28.8.0(@babel/parser@7.28.0)(vue@3.5.17(typescript@5.8.3))
|
||||
unplugin-vue-macros:
|
||||
specifier: ^2.14.5
|
||||
version: 2.14.5(@vueuse/core@9.13.0(vue@3.5.17(typescript@5.8.3)))(esbuild@0.25.6)(rollup@4.44.2)(typescript@5.8.3)(vite@7.0.3(@types/node@24.0.11)(jiti@2.4.2)(sass@1.89.2))(vue-tsc@3.0.1(typescript@5.8.3))(vue@3.5.17(typescript@5.8.3))
|
||||
@@ -166,9 +160,6 @@ packages:
|
||||
'@antfu/install-pkg@1.1.0':
|
||||
resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==}
|
||||
|
||||
'@antfu/utils@0.7.10':
|
||||
resolution: {integrity: sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==}
|
||||
|
||||
'@antfu/utils@8.1.1':
|
||||
resolution: {integrity: sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==}
|
||||
|
||||
@@ -509,18 +500,6 @@ packages:
|
||||
'@imengyu/vue3-context-menu@1.5.1':
|
||||
resolution: {integrity: sha512-Y3M/PVOj0Fz7lu3aviIu6NKFYjqMP1tZSffSiYy55JdAfcm/bD06dRT9RL5AccOqTSJdvcAImhiYvmBnPKtYEg==}
|
||||
|
||||
'@intlify/core-base@9.14.4':
|
||||
resolution: {integrity: sha512-vtZCt7NqWhKEtHa3SD/322DlgP5uR9MqWxnE0y8Q0tjDs9H5Lxhss+b5wv8rmuXRoHKLESNgw9d+EN9ybBbj9g==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/message-compiler@9.14.4':
|
||||
resolution: {integrity: sha512-vcyCLiVRN628U38c3PbahrhbbXrckrM9zpy0KZVlDk2Z0OnGwv8uQNNXP3twwGtfLsCf4gu3ci6FMIZnPaqZsw==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/shared@9.14.4':
|
||||
resolution: {integrity: sha512-P9zv6i1WvMc9qDBWvIgKkymjY2ptIiQ065PjDv7z7fDqH3J/HBRBN5IoiR46r/ujRcU7hCuSIZWvCAFCyuOYZA==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@isaacs/balanced-match@4.0.1':
|
||||
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
|
||||
engines: {node: 20 || >=22}
|
||||
@@ -545,18 +524,6 @@ packages:
|
||||
'@napi-rs/wasm-runtime@0.2.11':
|
||||
resolution: {integrity: sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==}
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
'@nodelib/fs.stat@2.0.5':
|
||||
resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
'@nodelib/fs.walk@1.2.8':
|
||||
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
'@opentranslate/baidu@1.4.2':
|
||||
resolution: {integrity: sha512-j8V7P+OCzEIAa+Zh4P6tbgWizVuVfKJOXDvk6M865J4QOE1lUQIN/Hb5SdodePkFinwNbQK2mAb7qF9wO/nQbA==}
|
||||
|
||||
@@ -1708,9 +1675,6 @@ packages:
|
||||
resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
daisyui@5.0.50:
|
||||
resolution: {integrity: sha512-c1PweK5RI1C76q58FKvbS4jzgyNJSP6CGTQ+KkZYzADdJoERnOxFoeLfDHmQgxLpjEzlYhFMXCeodQNLCC9bow==}
|
||||
|
||||
dayjs@1.11.13:
|
||||
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
|
||||
|
||||
@@ -1864,6 +1828,9 @@ packages:
|
||||
es-module-lexer@0.4.1:
|
||||
resolution: {integrity: sha512-ooYciCUtfw6/d2w56UVeqHPcoCFAiJdz5XOkYpv/Txl1HMUozpXjz/2RIQgqwKdXNDPSF1W7mJCFse3G+HDyAA==}
|
||||
|
||||
es-module-lexer@1.7.0:
|
||||
resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
|
||||
|
||||
es-object-atoms@1.1.1:
|
||||
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -1963,19 +1930,12 @@ packages:
|
||||
fast-deep-equal@3.1.3:
|
||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||
|
||||
fast-glob@3.3.3:
|
||||
resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
|
||||
engines: {node: '>=8.6.0'}
|
||||
|
||||
fast-levenshtein@1.1.4:
|
||||
resolution: {integrity: sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==}
|
||||
|
||||
fast-uri@3.0.6:
|
||||
resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==}
|
||||
|
||||
fastq@1.19.1:
|
||||
resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
|
||||
|
||||
fdir@6.4.6:
|
||||
resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==}
|
||||
peerDependencies:
|
||||
@@ -2545,14 +2505,6 @@ packages:
|
||||
resolution: {integrity: sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
local-pkg@0.4.3:
|
||||
resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
local-pkg@0.5.1:
|
||||
resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
local-pkg@1.1.1:
|
||||
resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==}
|
||||
engines: {node: '>=14'}
|
||||
@@ -2641,10 +2593,6 @@ packages:
|
||||
memoize-one@6.0.0:
|
||||
resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==}
|
||||
|
||||
merge2@1.4.1:
|
||||
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
merge@2.1.1:
|
||||
resolution: {integrity: sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==}
|
||||
|
||||
@@ -2985,9 +2933,6 @@ packages:
|
||||
quansync@0.2.10:
|
||||
resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==}
|
||||
|
||||
queue-microtask@1.2.3:
|
||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||
|
||||
read-pkg-up@1.0.1:
|
||||
resolution: {integrity: sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -3097,10 +3042,6 @@ packages:
|
||||
resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
reusify@1.1.0:
|
||||
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
|
||||
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
||||
|
||||
rfdc@1.4.1:
|
||||
resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
|
||||
|
||||
@@ -3131,9 +3072,6 @@ packages:
|
||||
resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==}
|
||||
engines: {node: '>=0.12.0'}
|
||||
|
||||
run-parallel@1.2.0:
|
||||
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
||||
|
||||
rxjs@7.8.2:
|
||||
resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==}
|
||||
|
||||
@@ -3321,8 +3259,8 @@ packages:
|
||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
strip-literal@2.1.1:
|
||||
resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==}
|
||||
strip-literal@3.0.0:
|
||||
resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==}
|
||||
|
||||
structured-source@4.0.0:
|
||||
resolution: {integrity: sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==}
|
||||
@@ -3462,8 +3400,9 @@ packages:
|
||||
undici-types@7.8.0:
|
||||
resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==}
|
||||
|
||||
unimport@3.14.6:
|
||||
resolution: {integrity: sha512-CYvbDaTT04Rh8bmD8jz3WPmHYZRG/NnvYVzwD6V1YAlvvKROlAeNDUBhkBGzNav2RKaeuXvlWYaa1V4Lfi/O0g==}
|
||||
unimport@4.2.0:
|
||||
resolution: {integrity: sha512-mYVtA0nmzrysnYnyb3ALMbByJ+Maosee2+WyE0puXl+Xm2bUwPorPaaeZt0ETfuroPOtG8jj1g/qeFZ6buFnag==}
|
||||
engines: {node: '>=18.12.0'}
|
||||
|
||||
union-value@1.0.1:
|
||||
resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==}
|
||||
@@ -3488,8 +3427,8 @@ packages:
|
||||
vite:
|
||||
optional: true
|
||||
|
||||
unplugin-auto-import@0.16.7:
|
||||
resolution: {integrity: sha512-w7XmnRlchq6YUFJVFGSvG1T/6j8GrdYN6Em9Wf0Ye+HXgD/22kont+WnuCAA0UaUoxtuvRR1u/mXKy63g/hfqQ==}
|
||||
unplugin-auto-import@19.3.0:
|
||||
resolution: {integrity: sha512-iIi0u4Gq2uGkAOGqlPJOAMI8vocvjh1clGTfSK4SOrJKrt+tirrixo/FjgBwXQNNdS7ofcr7OxzmOb/RjWxeEQ==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
'@nuxt/kit': ^3.2.2
|
||||
@@ -3527,16 +3466,20 @@ packages:
|
||||
webpack:
|
||||
optional: true
|
||||
|
||||
unplugin-element-plus@0.10.0:
|
||||
resolution: {integrity: sha512-oRSW0x6U58xBOWKy8TcoVZNA8ElIpfp3TUJRLQI6ey/E9PpjHl9/deeTAZNt8D57Li4OA4pCJtM6p2cb4Ff4ZA==}
|
||||
engines: {node: '>=18.12.0'}
|
||||
|
||||
unplugin-utils@0.2.4:
|
||||
resolution: {integrity: sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA==}
|
||||
engines: {node: '>=18.12.0'}
|
||||
|
||||
unplugin-vue-components@0.25.2:
|
||||
resolution: {integrity: sha512-OVmLFqILH6w+eM8fyt/d/eoJT9A6WO51NZLf1vC5c1FZ4rmq2bbGxTy8WP2Jm7xwFdukaIdv819+UI7RClPyCA==}
|
||||
unplugin-vue-components@28.8.0:
|
||||
resolution: {integrity: sha512-2Q6ZongpoQzuXDK0ZsVzMoshH0MWZQ1pzVL538G7oIDKRTVzHjppBDS8aB99SADGHN3lpGU7frraCG6yWNoL5Q==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
'@babel/parser': ^7.15.8
|
||||
'@nuxt/kit': ^3.2.2
|
||||
'@nuxt/kit': ^3.2.2 || ^4.0.0
|
||||
vue: 2 || 3
|
||||
peerDependenciesMeta:
|
||||
'@babel/parser':
|
||||
@@ -3558,6 +3501,10 @@ packages:
|
||||
resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
unplugin@2.3.5:
|
||||
resolution: {integrity: sha512-RyWSb5AHmGtjjNQ6gIlA67sHOsWpsbWpwDokLwTcejVdOjEkJZh7QKu14J00gDDVSh8kGH4KYC/TNBceXFZhtw==}
|
||||
engines: {node: '>=18.12.0'}
|
||||
|
||||
unset-value@1.0.0:
|
||||
resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -3675,12 +3622,6 @@ packages:
|
||||
vue-flow-layout@0.2.0:
|
||||
resolution: {integrity: sha512-zKgsWWkXq0xrus7H4Mc+uFs1ESrmdTXlO0YNbR6wMdPaFvosL3fMB8N7uTV308UhGy9UvTrGhIY7mVz9eN+L0Q==}
|
||||
|
||||
vue-i18n@9.14.4:
|
||||
resolution: {integrity: sha512-B934C8yUyWLT0EMud3DySrwSUJI7ZNiWYsEEz2gknTthqKiG4dzWE/WSa8AzCuSQzwBEv4HtG1jZDhgzPfWSKQ==}
|
||||
engines: {node: '>= 16'}
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
|
||||
vue-observe-visibility@2.0.0-alpha.1:
|
||||
resolution: {integrity: sha512-flFbp/gs9pZniXR6fans8smv1kDScJ8RS7rEpMjhVabiKeq7Qz3D9+eGsypncjfIyyU84saU88XZ0zjbD6Gq/g==}
|
||||
peerDependencies:
|
||||
@@ -3808,8 +3749,6 @@ snapshots:
|
||||
package-manager-detector: 1.3.0
|
||||
tinyexec: 1.0.1
|
||||
|
||||
'@antfu/utils@0.7.10': {}
|
||||
|
||||
'@antfu/utils@8.1.1': {}
|
||||
|
||||
'@babel/code-frame@7.27.1':
|
||||
@@ -4158,18 +4097,6 @@ snapshots:
|
||||
dependencies:
|
||||
'@imengyu/vue-scroll-rect': 0.1.4
|
||||
|
||||
'@intlify/core-base@9.14.4':
|
||||
dependencies:
|
||||
'@intlify/message-compiler': 9.14.4
|
||||
'@intlify/shared': 9.14.4
|
||||
|
||||
'@intlify/message-compiler@9.14.4':
|
||||
dependencies:
|
||||
'@intlify/shared': 9.14.4
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@intlify/shared@9.14.4': {}
|
||||
|
||||
'@isaacs/balanced-match@4.0.1': {}
|
||||
|
||||
'@isaacs/brace-expansion@5.0.0':
|
||||
@@ -4197,18 +4124,6 @@ snapshots:
|
||||
'@tybys/wasm-util': 0.9.0
|
||||
optional: true
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
dependencies:
|
||||
'@nodelib/fs.stat': 2.0.5
|
||||
run-parallel: 1.2.0
|
||||
|
||||
'@nodelib/fs.stat@2.0.5': {}
|
||||
|
||||
'@nodelib/fs.walk@1.2.8':
|
||||
dependencies:
|
||||
'@nodelib/fs.scandir': 2.1.5
|
||||
fastq: 1.19.1
|
||||
|
||||
'@opentranslate/baidu@1.4.2':
|
||||
dependencies:
|
||||
'@opentranslate/translator': 1.4.2
|
||||
@@ -5526,8 +5441,6 @@ snapshots:
|
||||
es5-ext: 0.10.64
|
||||
type: 2.7.3
|
||||
|
||||
daisyui@5.0.50: {}
|
||||
|
||||
dayjs@1.11.13: {}
|
||||
|
||||
de-indent@1.0.2: {}
|
||||
@@ -5666,6 +5579,8 @@ snapshots:
|
||||
|
||||
es-module-lexer@0.4.1: {}
|
||||
|
||||
es-module-lexer@1.7.0: {}
|
||||
|
||||
es-object-atoms@1.1.1:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
@@ -5821,23 +5736,11 @@ snapshots:
|
||||
fast-deep-equal@3.1.3:
|
||||
optional: true
|
||||
|
||||
fast-glob@3.3.3:
|
||||
dependencies:
|
||||
'@nodelib/fs.stat': 2.0.5
|
||||
'@nodelib/fs.walk': 1.2.8
|
||||
glob-parent: 5.1.2
|
||||
merge2: 1.4.1
|
||||
micromatch: 4.0.8
|
||||
|
||||
fast-levenshtein@1.1.4: {}
|
||||
|
||||
fast-uri@3.0.6:
|
||||
optional: true
|
||||
|
||||
fastq@1.19.1:
|
||||
dependencies:
|
||||
reusify: 1.1.0
|
||||
|
||||
fdir@6.4.6(picomatch@4.0.2):
|
||||
optionalDependencies:
|
||||
picomatch: 4.0.2
|
||||
@@ -6436,13 +6339,6 @@ snapshots:
|
||||
pinkie-promise: 2.0.1
|
||||
strip-bom: 2.0.0
|
||||
|
||||
local-pkg@0.4.3: {}
|
||||
|
||||
local-pkg@0.5.1:
|
||||
dependencies:
|
||||
mlly: 1.7.4
|
||||
pkg-types: 1.3.1
|
||||
|
||||
local-pkg@1.1.1:
|
||||
dependencies:
|
||||
mlly: 1.7.4
|
||||
@@ -6533,8 +6429,6 @@ snapshots:
|
||||
|
||||
memoize-one@6.0.0: {}
|
||||
|
||||
merge2@1.4.1: {}
|
||||
|
||||
merge@2.1.1: {}
|
||||
|
||||
micromatch@3.1.10:
|
||||
@@ -6894,8 +6788,6 @@ snapshots:
|
||||
|
||||
quansync@0.2.10: {}
|
||||
|
||||
queue-microtask@1.2.3: {}
|
||||
|
||||
read-pkg-up@1.0.1:
|
||||
dependencies:
|
||||
find-up: 1.1.2
|
||||
@@ -7010,8 +6902,6 @@ snapshots:
|
||||
|
||||
ret@0.1.15: {}
|
||||
|
||||
reusify@1.1.0: {}
|
||||
|
||||
rfdc@1.4.1: {}
|
||||
|
||||
rollup-plugin-external-globals@0.10.0(rollup@4.44.2):
|
||||
@@ -7059,10 +6949,6 @@ snapshots:
|
||||
|
||||
run-async@2.4.1: {}
|
||||
|
||||
run-parallel@1.2.0:
|
||||
dependencies:
|
||||
queue-microtask: 1.2.3
|
||||
|
||||
rxjs@7.8.2:
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
@@ -7270,7 +7156,7 @@ snapshots:
|
||||
|
||||
strip-json-comments@3.1.1: {}
|
||||
|
||||
strip-literal@2.1.1:
|
||||
strip-literal@3.0.0:
|
||||
dependencies:
|
||||
js-tokens: 9.0.1
|
||||
|
||||
@@ -7427,24 +7313,22 @@ snapshots:
|
||||
undici-types@7.8.0:
|
||||
optional: true
|
||||
|
||||
unimport@3.14.6(rollup@4.44.2):
|
||||
unimport@4.2.0:
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.2.0(rollup@4.44.2)
|
||||
acorn: 8.15.0
|
||||
escape-string-regexp: 5.0.0
|
||||
estree-walker: 3.0.3
|
||||
fast-glob: 3.3.3
|
||||
local-pkg: 1.1.1
|
||||
magic-string: 0.30.17
|
||||
mlly: 1.7.4
|
||||
pathe: 2.0.3
|
||||
picomatch: 4.0.2
|
||||
pkg-types: 1.3.1
|
||||
pkg-types: 2.2.0
|
||||
scule: 1.3.0
|
||||
strip-literal: 2.1.1
|
||||
unplugin: 1.16.1
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
strip-literal: 3.0.0
|
||||
tinyglobby: 0.2.14
|
||||
unplugin: 2.3.5
|
||||
unplugin-utils: 0.2.4
|
||||
|
||||
union-value@1.0.1:
|
||||
dependencies:
|
||||
@@ -7487,20 +7371,16 @@ snapshots:
|
||||
- postcss
|
||||
- supports-color
|
||||
|
||||
unplugin-auto-import@0.16.7(@vueuse/core@9.13.0(vue@3.5.17(typescript@5.8.3)))(rollup@4.44.2):
|
||||
unplugin-auto-import@19.3.0(@vueuse/core@9.13.0(vue@3.5.17(typescript@5.8.3))):
|
||||
dependencies:
|
||||
'@antfu/utils': 0.7.10
|
||||
'@rollup/pluginutils': 5.2.0(rollup@4.44.2)
|
||||
fast-glob: 3.3.3
|
||||
local-pkg: 0.5.1
|
||||
local-pkg: 1.1.1
|
||||
magic-string: 0.30.17
|
||||
minimatch: 9.0.5
|
||||
unimport: 3.14.6(rollup@4.44.2)
|
||||
unplugin: 1.16.1
|
||||
picomatch: 4.0.2
|
||||
unimport: 4.2.0
|
||||
unplugin: 2.3.5
|
||||
unplugin-utils: 0.2.4
|
||||
optionalDependencies:
|
||||
'@vueuse/core': 9.13.0(vue@3.5.17(typescript@5.8.3))
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
|
||||
unplugin-combine@1.2.1(esbuild@0.25.6)(rollup@4.44.2)(unplugin@1.16.1)(vite@7.0.3(@types/node@24.0.11)(jiti@2.4.2)(sass@1.89.2)):
|
||||
optionalDependencies:
|
||||
@@ -7509,28 +7389,32 @@ snapshots:
|
||||
unplugin: 1.16.1
|
||||
vite: 7.0.3(@types/node@24.0.11)(jiti@2.4.2)(sass@1.89.2)
|
||||
|
||||
unplugin-element-plus@0.10.0:
|
||||
dependencies:
|
||||
es-module-lexer: 1.7.0
|
||||
magic-string: 0.30.17
|
||||
unplugin: 2.3.5
|
||||
unplugin-utils: 0.2.4
|
||||
|
||||
unplugin-utils@0.2.4:
|
||||
dependencies:
|
||||
pathe: 2.0.3
|
||||
picomatch: 4.0.2
|
||||
|
||||
unplugin-vue-components@0.25.2(@babel/parser@7.28.0)(rollup@4.44.2)(vue@3.5.17(typescript@5.8.3)):
|
||||
unplugin-vue-components@28.8.0(@babel/parser@7.28.0)(vue@3.5.17(typescript@5.8.3)):
|
||||
dependencies:
|
||||
'@antfu/utils': 0.7.10
|
||||
'@rollup/pluginutils': 5.2.0(rollup@4.44.2)
|
||||
chokidar: 3.6.0
|
||||
debug: 4.4.1
|
||||
fast-glob: 3.3.3
|
||||
local-pkg: 0.4.3
|
||||
local-pkg: 1.1.1
|
||||
magic-string: 0.30.17
|
||||
minimatch: 9.0.5
|
||||
resolve: 1.22.10
|
||||
unplugin: 1.16.1
|
||||
mlly: 1.7.4
|
||||
tinyglobby: 0.2.14
|
||||
unplugin: 2.3.5
|
||||
unplugin-utils: 0.2.4
|
||||
vue: 3.5.17(typescript@5.8.3)
|
||||
optionalDependencies:
|
||||
'@babel/parser': 7.28.0
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
- supports-color
|
||||
|
||||
unplugin-vue-define-options@1.5.5(vue@3.5.17(typescript@5.8.3)):
|
||||
@@ -7592,6 +7476,12 @@ snapshots:
|
||||
acorn: 8.15.0
|
||||
webpack-virtual-modules: 0.6.2
|
||||
|
||||
unplugin@2.3.5:
|
||||
dependencies:
|
||||
acorn: 8.15.0
|
||||
picomatch: 4.0.2
|
||||
webpack-virtual-modules: 0.6.2
|
||||
|
||||
unset-value@1.0.0:
|
||||
dependencies:
|
||||
has-value: 0.3.1
|
||||
@@ -7701,13 +7591,6 @@ snapshots:
|
||||
|
||||
vue-flow-layout@0.2.0: {}
|
||||
|
||||
vue-i18n@9.14.4(vue@3.5.17(typescript@5.8.3)):
|
||||
dependencies:
|
||||
'@intlify/core-base': 9.14.4
|
||||
'@intlify/shared': 9.14.4
|
||||
'@vue/devtools-api': 6.6.4
|
||||
vue: 3.5.17(typescript@5.8.3)
|
||||
|
||||
vue-observe-visibility@2.0.0-alpha.1(vue@3.5.17(typescript@5.8.3)):
|
||||
dependencies:
|
||||
vue: 3.5.17(typescript@5.8.3)
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
//@import '/node_modules/element-plus/dist/index.css';
|
||||
@use "anim" as *;
|
||||
@use 'element-plus/theme-chalk/dark/css-vars' as *;
|
||||
|
||||
:root {
|
||||
//修改element-ui的进度条底色
|
||||
--el-border-color-lighter: #d1d1d1 !important;
|
||||
|
||||
--color-item-bg: rgb(228, 230, 232);
|
||||
--color-item-hover: white;
|
||||
//--color-item-active: rgb(75, 110, 175);
|
||||
@@ -23,12 +18,12 @@
|
||||
--practice-wrapper-translateX: 1px;
|
||||
--article-width: 50vw;
|
||||
--toolbar-width: 50rem;
|
||||
--toolbar-height: 3.2rem;
|
||||
--panel-width: 24rem;
|
||||
--space: 1rem;
|
||||
--stat-gap: 2rem;
|
||||
--shadow: rgba(0, 0, 0, 0.08) 0px 4px 12px;
|
||||
--panel-margin-left: calc(50% + var(--toolbar-width) / 2 + 1rem);
|
||||
--article-panel-margin-left: calc(50% + var(--article-width) / 2 + 3.5rem);
|
||||
--article-panel-margin-left: calc(50% + var(--article-width) / 2 + 1rem);
|
||||
--anim-time: 0.3s;
|
||||
|
||||
--color-input-bg: white;
|
||||
@@ -46,7 +41,7 @@
|
||||
--zh-article-family: "Songti SC", "SimSun", "Noto Serif CJK SC", serif;
|
||||
|
||||
--btn-primary: rgb(75, 85, 99);
|
||||
--btn-info: #909399;
|
||||
--btn-info: white;
|
||||
|
||||
--color-primary: #E6E8EB;
|
||||
--color-second: rgb(247, 247, 247);
|
||||
@@ -54,7 +49,7 @@
|
||||
|
||||
--color-card-active: #FED7AA;
|
||||
--color-list-item-active: rgb(253, 246, 236);
|
||||
--color-icon-hightlight: #E6A23C;
|
||||
--color-icon-hightlight: rgb(12, 140, 233);
|
||||
//--color-icon-hightlight: rgb(12, 140, 233);
|
||||
--color-sub-text: gray;
|
||||
--color-main-text: rgb(91, 91, 91);
|
||||
@@ -62,15 +57,26 @@
|
||||
--color-select-text: white;
|
||||
|
||||
--color-notice-bg: rgb(247, 247, 247);
|
||||
|
||||
|
||||
//修改element-ui的进度条底色
|
||||
--el-border-color-lighter: #e2e5ed !important;
|
||||
}
|
||||
|
||||
.footer {
|
||||
&.hide {
|
||||
--el-border-color-lighter: #dbdbdb !important;
|
||||
}
|
||||
}
|
||||
|
||||
html.dark {
|
||||
|
||||
--color-primary: #0E1217;
|
||||
--color-second: rgb(30, 31, 34);
|
||||
--color-third: rgb(43, 45, 48);
|
||||
--color-card-active: rgb(84, 84, 84);
|
||||
--color-list-item-active: rgb(84, 84, 84);
|
||||
--color-icon-hightlight: #E6A23C;
|
||||
--color-icon-hightlight: rgb(147, 173, 227);
|
||||
--color-sub-text: #b8b8b8;
|
||||
--color-main-text: rgba(249, 250, 251, 0.8);
|
||||
--color-select-bg: rgb(147, 173, 227);
|
||||
@@ -88,65 +94,51 @@ html.dark {
|
||||
--color-font-3: rgba(255, 255, 255, 0.3);
|
||||
|
||||
--color-sub-gray: #383737;
|
||||
|
||||
--color-scrollbar: rgb(92, 93, 94);
|
||||
|
||||
--btn-info: transparent;
|
||||
|
||||
--color-input-bg: rgba(14, 18, 23, 1);
|
||||
--color-input-icon: #383737;
|
||||
|
||||
--color-textarea-bg: rgb(43, 45, 48);
|
||||
--color-article: white;
|
||||
|
||||
--el-border-color-lighter: var(--color-third) !important;
|
||||
|
||||
.footer {
|
||||
&.hide {
|
||||
--el-border-color-lighter: var(--color-third) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1680px) {
|
||||
:root {
|
||||
--practice-wrapper-translateX: -12vw;
|
||||
--toolbar-width: 40vw;
|
||||
--article-width: 60vw;
|
||||
--panel-width: 38rem;
|
||||
--toolbar-height: 4.8rem;
|
||||
--panel-margin-left: calc(50vw + var(--practice-wrapper-translateX) + var(--toolbar-width) / 2 + 5vw);
|
||||
--article-panel-margin-left: calc(50% + var(--practice-wrapper-translateX) + var(--article-width) / 2 + 48rem);
|
||||
--toolbar-width: 50vw;
|
||||
--article-width: 50vw;
|
||||
--panel-width: 20vw;
|
||||
--space: 0.5rem;
|
||||
}
|
||||
.footer {
|
||||
.bottom {
|
||||
padding: 1.5rem 1rem 1rem 1rem !important;
|
||||
}
|
||||
|
||||
.stat {
|
||||
margin-top: 0.4rem !important;
|
||||
|
||||
.row {
|
||||
gap: 0.5rem !important;
|
||||
}
|
||||
padding: .5rem !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1366px) {
|
||||
:root {
|
||||
--space: 1rem;
|
||||
--practice-wrapper-translateX: -22vw;
|
||||
--article-width: 53vw;
|
||||
--panel-width: 30vw;
|
||||
--panel-width: 20vw;
|
||||
--article-width: 50vw;
|
||||
--toolbar-width: 50vw;
|
||||
--toolbar-height: 40rem;
|
||||
--panel-margin-left: calc(50vw + var(--practice-wrapper-translateX) + var(--toolbar-width) / 2 + 14vw);
|
||||
--article-panel-margin-left: calc(50% + var(--practice-wrapper-translateX) + var(--article-width) / 2 + 12vw);
|
||||
--stat-gap: 0.5rem;
|
||||
--space: 0.3rem;
|
||||
}
|
||||
|
||||
.footer {
|
||||
.bottom {
|
||||
padding: 1.5rem 0.5rem 0.5rem 0.5rem !important;
|
||||
}
|
||||
|
||||
.stat {
|
||||
margin-top: 0.4rem !important;
|
||||
|
||||
.row {
|
||||
gap: 0.5rem !important;
|
||||
}
|
||||
padding: .5rem !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -397,7 +389,6 @@ footer {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.item-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -30,7 +30,6 @@ defineEmits(['click'])
|
||||
size,
|
||||
type,
|
||||
(disabled||loading) && 'disabled',
|
||||
!disabled && 'hvr-grow'
|
||||
]">
|
||||
<span :style="{opacity:loading?0:1}"><slot></slot></span>
|
||||
<Icon v-if="loading"
|
||||
@@ -51,19 +50,25 @@ defineEmits(['click'])
|
||||
|
||||
.base-button {
|
||||
cursor: pointer;
|
||||
border-radius: .4rem;
|
||||
padding: 0 1rem;
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all .3s;
|
||||
//background: #999;
|
||||
//background: rgb(60, 63, 65);
|
||||
//background: var(--color-second);
|
||||
height: 2.5rem;
|
||||
line-height: 1;
|
||||
position: relative;
|
||||
word-break: keep-all;
|
||||
outline: none;
|
||||
text-align: center;
|
||||
transition: .1s;
|
||||
user-select: none;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
border-radius: .3rem;
|
||||
padding: 0 0.9rem;
|
||||
font-size: .9rem;
|
||||
height: 2rem;
|
||||
color: white;
|
||||
|
||||
& + .base-button {
|
||||
margin-left: var(--space);
|
||||
}
|
||||
|
||||
.loading {
|
||||
position: absolute;
|
||||
@@ -76,27 +81,21 @@ defineEmits(['click'])
|
||||
}
|
||||
|
||||
&.small {
|
||||
height: 2.4rem;
|
||||
|
||||
& > span {
|
||||
font-size: .8rem;
|
||||
}
|
||||
border-radius: 0.2rem;
|
||||
padding: 0 0.8rem;
|
||||
height: 1.6rem;
|
||||
font-size: .8rem;
|
||||
}
|
||||
|
||||
&.large {
|
||||
height: 3rem;
|
||||
font-size: 1.1rem;
|
||||
padding: 0 1.4rem;
|
||||
|
||||
& > span {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
padding: 0 1.3rem;
|
||||
height: 2.4rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
|
||||
& > span {
|
||||
font-size: 1rem;
|
||||
color: white;
|
||||
line-height: 1;
|
||||
transform: translateY(-5%);
|
||||
|
||||
:deep(a) {
|
||||
color: white;
|
||||
@@ -104,10 +103,9 @@ defineEmits(['click'])
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: .7;
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
|
||||
&.primary {
|
||||
background: var(--btn-primary);
|
||||
}
|
||||
@@ -117,12 +115,14 @@ defineEmits(['click'])
|
||||
border-bottom: 2px solid transparent;
|
||||
|
||||
&:hover {
|
||||
border-bottom: 2px solid var(--color-font-1);
|
||||
border-bottom: 2px solid var(--color-font-2);
|
||||
}
|
||||
}
|
||||
|
||||
&.info {
|
||||
background: var(--btn-info);
|
||||
border: 1px solid var(--color-main-text);
|
||||
color: var(--color-main-text);
|
||||
}
|
||||
|
||||
&.active {
|
||||
|
||||
@@ -43,7 +43,7 @@ $w: 1.4rem;
|
||||
transition: all .3s;
|
||||
|
||||
&:hover:not(.disabled) {
|
||||
background: var(--color-primary);
|
||||
background: var(--color-icon-hightlight);
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
2
src/global.d.ts
vendored
2
src/global.d.ts
vendored
@@ -1,4 +1,4 @@
|
||||
import {cloneDeep} from "lodash-es"
|
||||
import {cloneDeep} from "@/utils"
|
||||
|
||||
export {}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Article, ArticleWord, DictType, getDefaultArticleWord, Sentence} from "@/types.ts";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {cloneDeep} from "@/utils";
|
||||
import nlp from "compromise/one";
|
||||
import {usePlayWordAudio} from "@/hooks/sound.ts";
|
||||
import {getSentenceAllText, getSentenceAllTranslateText} from "@/hooks/translate.ts";
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import {Article, Dict, Word} from "@/types.ts";
|
||||
import {Article, Word} from "@/types.ts";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import {cloneDeep,} from "lodash-es";
|
||||
import {isArticle} from "@/hooks/article.ts";
|
||||
|
||||
|
||||
export function useWordOptions() {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {Article, Sentence, TranslateEngine} from "@/types.ts";
|
||||
import Baidu from "@opentranslate/baidu";
|
||||
import {axiosInstance} from "@/utils/http.ts";
|
||||
import {Translator} from "@opentranslate/translator/src/translator.ts";
|
||||
|
||||
export function getSentenceAllTranslateText(article: Article) {
|
||||
@@ -27,7 +26,6 @@ export async function getNetworkTranslate(
|
||||
let translator: Translator
|
||||
if (translateEngine === TranslateEngine.Baidu) {
|
||||
translator = new Baidu({
|
||||
axios: axiosInstance as any,
|
||||
config: {
|
||||
appid: "20230910001811857",
|
||||
key: "Xxe_yftQR3K3Ue43NQMC"
|
||||
|
||||
11
src/main.ts
11
src/main.ts
@@ -3,28 +3,17 @@ import './assets/css/style.scss'
|
||||
import 'virtual:uno.css';
|
||||
import App from './App.vue'
|
||||
import {createPinia} from "pinia"
|
||||
import ZH from "@/locales/zh-CN.ts";
|
||||
import {createI18n} from 'vue-i18n'
|
||||
import router from "@/router.ts";
|
||||
import VueVirtualScroller from 'vue-virtual-scroller'
|
||||
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
|
||||
import './global.d.ts'
|
||||
|
||||
const i18n = createI18n({
|
||||
locale: 'zh-CN',
|
||||
fallbackLocale: 'zh-CN',
|
||||
messages: {
|
||||
'zh-CN': ZH
|
||||
},
|
||||
})
|
||||
|
||||
const pinia = createPinia()
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(VueVirtualScroller)
|
||||
// app.use(ElementPlus)
|
||||
app.use(pinia)
|
||||
app.use(i18n)
|
||||
app.use(router)
|
||||
|
||||
app.directive('opacity', (el, binding) => {
|
||||
|
||||
@@ -4,7 +4,7 @@ import {ref, watch} from "vue";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {getAudioFileUrl, useChangeAllSound, usePlayAudio, useWatchAllSound} from "@/hooks/sound.ts";
|
||||
import {getShortcutKey, useDisableEventListener, useEventListener} from "@/hooks/event.ts";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {cloneDeep} from "@/utils";
|
||||
import {DefaultShortcutKeyMap, ShortcutKey} from "@/types.ts";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import {APP_NAME, EXPORT_DATA_KEY, SAVE_DICT_KEY, SAVE_SETTING_KEY, SoundFileOptions} from "@/utils/const.ts";
|
||||
@@ -15,7 +15,7 @@ import {checkAndUpgradeSaveDict, checkAndUpgradeSaveSetting, shakeCommonDict} fr
|
||||
import {GITHUB} from "@/config/ENV.ts";
|
||||
import dayjs from "dayjs";
|
||||
import BasePage from "@/pages/pc/components/BasePage.vue";
|
||||
|
||||
import {ElSwitch, ElSelect, ElOption, ElSlider, ElRadioGroup, ElRadio, ElInputNumber} from 'element-plus'
|
||||
|
||||
const emit = defineEmits<{
|
||||
toggleDisabledDialogEscKey: [val: boolean]
|
||||
@@ -162,11 +162,11 @@ function importData(e) {
|
||||
<div class="row">
|
||||
<label class="main-title">所有音效</label>
|
||||
<div class="wrapper">
|
||||
<el-switch v-model="settingStore.allSound"
|
||||
@change="useChangeAllSound"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
<ElSwitch v-model="settingStore.allSound"
|
||||
@change="useChangeAllSound"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -174,35 +174,35 @@ function importData(e) {
|
||||
<div class="row">
|
||||
<label class="item-title">单词/句子自动发音</label>
|
||||
<div class="wrapper">
|
||||
<el-switch v-model="settingStore.wordSound"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
<ElSwitch v-model="settingStore.wordSound"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="sub-title">单词/句子发音口音</label>
|
||||
<div class="wrapper">
|
||||
<el-select v-model="settingStore.wordSoundType"
|
||||
placeholder="请选择"
|
||||
<ElSelect v-model="settingStore.wordSoundType"
|
||||
placeholder="请选择"
|
||||
>
|
||||
<el-option label="美音" value="us"/>
|
||||
<el-option label="英音" value="uk"/>
|
||||
</el-select>
|
||||
<ElOption label="美音" value="us"/>
|
||||
<ElOption label="英音" value="uk"/>
|
||||
</ElSelect>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="sub-title">音量</label>
|
||||
<div class="wrapper">
|
||||
<el-slider v-model="settingStore.wordSoundVolume"/>
|
||||
<ElSlider v-model="settingStore.wordSoundVolume"/>
|
||||
<span>{{ settingStore.wordSoundVolume }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="sub-title">倍速</label>
|
||||
<div class="wrapper">
|
||||
<el-slider v-model="settingStore.wordSoundSpeed" :step="0.1" :min="0.5" :max="3"/>
|
||||
<ElSlider v-model="settingStore.wordSoundSpeed" :step="0.1" :min="0.5" :max="3"/>
|
||||
<span>{{ settingStore.wordSoundSpeed }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -210,20 +210,20 @@ function importData(e) {
|
||||
<div class="row">
|
||||
<label class="item-title">按键音</label>
|
||||
<div class="wrapper">
|
||||
<el-switch v-model="settingStore.keyboardSound"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
<ElSwitch v-model="settingStore.keyboardSound"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="item-title">按键音效</label>
|
||||
<div class="wrapper">
|
||||
<el-select v-model="settingStore.keyboardSoundFile"
|
||||
placeholder="请选择"
|
||||
<ElSelect v-model="settingStore.keyboardSoundFile"
|
||||
placeholder="请选择"
|
||||
>
|
||||
<el-option
|
||||
<ElOption
|
||||
v-for="item in SoundFileOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
@@ -235,14 +235,14 @@ function importData(e) {
|
||||
:time="100"
|
||||
@click="usePlayAudio(getAudioFileUrl(item.value)[0])"/>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</ElOption>
|
||||
</ElSelect>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="sub-title">音量</label>
|
||||
<div class="wrapper">
|
||||
<el-slider v-model="settingStore.keyboardSoundVolume"/>
|
||||
<ElSlider v-model="settingStore.keyboardSoundVolume"/>
|
||||
<span>{{ settingStore.keyboardSoundVolume }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -250,17 +250,17 @@ function importData(e) {
|
||||
<div class="row">
|
||||
<label class="item-title">效果音(输入错误、完成时的音效)</label>
|
||||
<div class="wrapper">
|
||||
<el-switch v-model="settingStore.effectSound"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
<ElSwitch v-model="settingStore.effectSound"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="sub-title">音量</label>
|
||||
<div class="wrapper">
|
||||
<el-slider v-model="settingStore.effectSoundVolume"/>
|
||||
<ElSlider v-model="settingStore.effectSoundVolume"/>
|
||||
<span>{{ settingStore.effectSoundVolume }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -269,19 +269,19 @@ function importData(e) {
|
||||
<div class="row">
|
||||
<label class="item-title">单词循环设置</label>
|
||||
<div class="wrapper">
|
||||
<el-radio-group v-model="settingStore.repeatCount">
|
||||
<el-radio :value="1" size="default">1</el-radio>
|
||||
<el-radio :value="2" size="default">2</el-radio>
|
||||
<el-radio :value="3" size="default">3</el-radio>
|
||||
<el-radio :value="5" size="default">5</el-radio>
|
||||
<el-radio :value="100" size="default">自定义</el-radio>
|
||||
</el-radio-group>
|
||||
<ElRadioGroup v-model="settingStore.repeatCount">
|
||||
<ElRadio :value="1" size="default">1</ElRadio>
|
||||
<ElRadio :value="2" size="default">2</ElRadio>
|
||||
<ElRadio :value="3" size="default">3</ElRadio>
|
||||
<ElRadio :value="5" size="default">5</ElRadio>
|
||||
<ElRadio :value="100" size="default">自定义</ElRadio>
|
||||
</ElRadioGroup>
|
||||
<div class="mini-row" v-if="settingStore.repeatCount === 100">
|
||||
<label class="item-title">循环次数</label>
|
||||
<el-input-number v-model="settingStore.repeatCustomCount"
|
||||
:min="6"
|
||||
:max="15"
|
||||
type="number"
|
||||
<ElInputNumber v-model="settingStore.repeatCustomCount"
|
||||
:min="6"
|
||||
:max="15"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -289,10 +289,10 @@ function importData(e) {
|
||||
<div class="row">
|
||||
<label class="item-title">显示上一个/下一个单词</label>
|
||||
<div class="wrapper">
|
||||
<el-switch v-model="settingStore.showNearWord"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
<ElSwitch v-model="settingStore.showNearWord"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -303,10 +303,10 @@ function importData(e) {
|
||||
<div class="row">
|
||||
<label class="item-title">忽略大小写</label>
|
||||
<div class="wrapper">
|
||||
<el-switch v-model="settingStore.ignoreCase"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
<ElSwitch v-model="settingStore.ignoreCase"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -317,10 +317,10 @@ function importData(e) {
|
||||
<div class="row">
|
||||
<label class="item-title">允许默写模式下显示提示</label>
|
||||
<div class="wrapper">
|
||||
<el-switch v-model="settingStore.allowWordTip"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
<ElSwitch v-model="settingStore.allowWordTip"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -334,7 +334,7 @@ function importData(e) {
|
||||
<div class="row">
|
||||
<label class="sub-title">外语字体</label>
|
||||
<div class="wrapper">
|
||||
<el-slider
|
||||
<ElSlider
|
||||
:min="10"
|
||||
:max="100"
|
||||
v-model="settingStore.fontSize.wordForeignFontSize"/>
|
||||
@@ -344,7 +344,7 @@ function importData(e) {
|
||||
<div class="row">
|
||||
<label class="sub-title">中文字体</label>
|
||||
<div class="wrapper">
|
||||
<el-slider
|
||||
<ElSlider
|
||||
:min="10"
|
||||
:max="100"
|
||||
v-model="settingStore.fontSize.wordTranslateFontSize"/>
|
||||
@@ -359,10 +359,10 @@ function importData(e) {
|
||||
<div class="row">
|
||||
<label class="sub-title">切换下一个单词时间</label>
|
||||
<div class="wrapper">
|
||||
<el-input-number v-model="settingStore.waitTimeForChangeWord"
|
||||
:min="6"
|
||||
:max="100"
|
||||
type="number"
|
||||
<ElInputNumber v-model="settingStore.waitTimeForChangeWord"
|
||||
:min="6"
|
||||
:max="100"
|
||||
type="number"
|
||||
/>
|
||||
<span>毫秒</span>
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,7 @@ import {enArticle} from "@/assets/dictionary.ts";
|
||||
import BasePage from "@/pages/pc/components/BasePage.vue";
|
||||
import {useNav} from "@/utils";
|
||||
import {Dict, DictResource, getDefaultDict} from "@/types.ts";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {cloneDeep} from "@/utils";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {getArticleBookDataByUrl} from "@/utils/article.ts";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
@@ -15,6 +15,7 @@ import Dialog from "@/pages/pc/components/dialog/Dialog.vue";
|
||||
import Input from "@/pages/pc/components/Input.vue";
|
||||
import {computed} from "vue";
|
||||
import Book from "@/pages/pc/components/Book.vue";
|
||||
import {ElProgress} from 'element-plus';
|
||||
|
||||
const {nav} = useNav()
|
||||
const base = useBaseStore()
|
||||
@@ -71,7 +72,7 @@ function startStudy() {
|
||||
<BasePage>
|
||||
<div class="card ">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="bg-slate-200 p-3 gap-4 rounded-md cursor-pointer flex items-center">
|
||||
<div class="bg-third p-3 gap-4 rounded-md cursor-pointer flex items-center">
|
||||
<span class="text-lg font-bold"
|
||||
@click="getBookDetail2(base.currentBook)">{{
|
||||
base.currentBook.name || '请选择书籍开始学习'
|
||||
@@ -86,7 +87,7 @@ function startStudy() {
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 text-sm">已学习{{ base.currentBook.lastLearnIndex }}篇文章</div>
|
||||
<el-progress class="mt-1" :percentage="base.currentBookProgress" :show-text="false"></el-progress>
|
||||
<ElProgress class="mt-1" :percentage="base.currentBookProgress" :show-text="false"></ElProgress>
|
||||
</div>
|
||||
|
||||
<div class="card flex flex-col">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import {onMounted, onUnmounted} from "vue";
|
||||
import {Article, getDefaultArticle} from "@/types.ts";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {cloneDeep} from "@/utils";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
|
||||
import List from "@/pages/pc/components/list/List.vue";
|
||||
|
||||
@@ -11,7 +11,6 @@ import BaseButton from "@/components/BaseButton.vue";
|
||||
import {useRoute, useRouter} from "vue-router";
|
||||
import EditBook from "@/pages/pc/article/components/EditBook.vue";
|
||||
import {computed, onMounted} from "vue";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
|
||||
const runtimeStore = useRuntimeStore()
|
||||
const base = useBaseStore()
|
||||
@@ -73,7 +72,7 @@ function formClose() {
|
||||
<div class="flex justify-between items-center relative">
|
||||
<BackIcon class="z-2" @click="$router.back"/>
|
||||
<div class="absolute text-2xl text-align-center w-full">{{ runtimeStore.editDict.name }}</div>
|
||||
<div class="flex gap-2">
|
||||
<div class="flex">
|
||||
<BaseButton type="info" @click="isEdit = true">编辑</BaseButton>
|
||||
<BaseButton type="info" @click="router.push('batch-edit-article')">文章管理</BaseButton>
|
||||
<BaseButton @click="addMyStudyList">学习</BaseButton>
|
||||
|
||||
@@ -6,11 +6,10 @@ import EditAbleText from "@/pages/pc/components/EditAbleText.vue";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import {getNetworkTranslate, getSentenceAllText, getSentenceAllTranslateText} from "@/hooks/translate.ts";
|
||||
import {genArticleSectionData, splitCNArticle2, splitEnArticle2, usePlaySentenceAudio} from "@/hooks/article.ts";
|
||||
import {cloneDeep, last} from "lodash-es";
|
||||
import {_nextTick, _parseLRC, cloneDeep, last} from "@/utils";
|
||||
import {watch} from "vue";
|
||||
import Empty from "@/components/Empty.vue";
|
||||
import {UploadProps} from "element-plus";
|
||||
import {_nextTick, _parseLRC} from "@/utils";
|
||||
import {ElInputNumber, ElOption, ElPopover, ElSelect, ElUpload, UploadProps} from "element-plus";
|
||||
import * as Comparison from "string-comparison"
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import Dialog from "@/pages/pc/components/dialog/Dialog.vue";
|
||||
@@ -286,13 +285,13 @@ function setStartTime(val: Sentence, i: number, j: number) {
|
||||
>
|
||||
</textarea>
|
||||
<div class="justify-end items-center flex">
|
||||
<el-popover
|
||||
<ElPopover
|
||||
class="box-item"
|
||||
title="使用方法"
|
||||
placement="top"
|
||||
:width="400"
|
||||
>
|
||||
<ol class="py-0 pl-5 my-0 text-base color-black/60">
|
||||
<ol class="py-0 pl-5 my-0 text-base color-main">
|
||||
<li>复制原文,然后分句</li>
|
||||
<li>点击 <span class="color-red font-bold">分句</span> 按钮进行自动分句<span
|
||||
class="color-red font-bold"> 或</span> 手动编辑分句
|
||||
@@ -304,9 +303,9 @@ function setStartTime(val: Sentence, i: number, j: number) {
|
||||
<template #reference>
|
||||
<Icon icon="ri:question-line" class="mr-3" width="20"/>
|
||||
</template>
|
||||
</el-popover>
|
||||
<el-button type="primary" @click="splitText">分句</el-button>
|
||||
<el-button type="primary" @click="() => apply()">应用</el-button>
|
||||
</ElPopover>
|
||||
<BaseButton @click="splitText">分句</BaseButton>
|
||||
<BaseButton @click="apply()">应用</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row flex flex-col gap-2">
|
||||
@@ -334,27 +333,23 @@ function setStartTime(val: Sentence, i: number, j: number) {
|
||||
>
|
||||
</textarea>
|
||||
<div class="justify-between items-center flex">
|
||||
<div class="flex gap-2 items-center ">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="startNetworkTranslate"
|
||||
:loading="progress!==0 && progress !== 100"
|
||||
>翻译
|
||||
</el-button>
|
||||
<el-select v-model="networkTranslateEngine"
|
||||
class="w-20"
|
||||
<div class="flex gap-space items-center w-50 ">
|
||||
<BaseButton @click="startNetworkTranslate"
|
||||
:loading="progress!==0 && progress !== 100">翻译
|
||||
</BaseButton>
|
||||
<ElSelect v-model="networkTranslateEngine"
|
||||
>
|
||||
<el-option
|
||||
<ElOption
|
||||
v-for="item in TranslateEngineOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</ElSelect>
|
||||
{{ progress }}%
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<el-popover
|
||||
<ElPopover
|
||||
class="box-item"
|
||||
title="使用方法"
|
||||
placement="top"
|
||||
@@ -372,9 +367,9 @@ function setStartTime(val: Sentence, i: number, j: number) {
|
||||
<template #reference>
|
||||
<Icon icon="ri:question-line" class="mr-3" width="20"/>
|
||||
</template>
|
||||
</el-popover>
|
||||
<el-button type="primary" @click="splitTranslateText">分句</el-button>
|
||||
<el-button type="primary" @click="apply(true)">应用</el-button>
|
||||
</ElPopover>
|
||||
<BaseButton @click="splitTranslateText">分句</BaseButton>
|
||||
<BaseButton @click="apply(true)">应用</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -383,14 +378,14 @@ function setStartTime(val: Sentence, i: number, j: number) {
|
||||
<div class="center">正文、译文与结果均可编辑,编辑后点击应用按钮会自动同步</div>
|
||||
<div class="flex gap-2">
|
||||
<BaseButton>添加音频</BaseButton>
|
||||
<el-upload
|
||||
<ElUpload
|
||||
class="upload-demo"
|
||||
:limit="1"
|
||||
:on-change="handleChange"
|
||||
:auto-upload="false"
|
||||
>
|
||||
<el-button type="primary">添加音频LRC文件</el-button>
|
||||
</el-upload>
|
||||
<BaseButton>添加音频LRC文件</BaseButton>
|
||||
</ElUpload>
|
||||
<audio ref="audioRef" :src="editArticle.audioSrc" controls></audio>
|
||||
</div>
|
||||
<template v-if="editArticle.sections.length">
|
||||
@@ -498,11 +493,11 @@ function setStartTime(val: Sentence, i: number, j: number) {
|
||||
<div>开始时间:</div>
|
||||
<div class="flex justify-between flex-1">
|
||||
<div class="flex items-center gap-2">
|
||||
<el-input-number v-model="editSentence.audioPosition[0]" :precision="2" :step="0.1">
|
||||
<ElInputNumber v-model="editSentence.audioPosition[0]" :precision="2" :step="0.1">
|
||||
<template #suffix>
|
||||
<span>s</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</ElInputNumber>
|
||||
<BaseIcon
|
||||
@click="jumpAudio(editSentence.audioPosition[0])"
|
||||
title="跳转"
|
||||
@@ -521,11 +516,11 @@ function setStartTime(val: Sentence, i: number, j: number) {
|
||||
<div>结束时间:</div>
|
||||
<div class="flex justify-between flex-1">
|
||||
<div class="flex items-center gap-2">
|
||||
<el-input-number v-model="editSentence.audioPosition[1]" :precision="2" :step="0.1">
|
||||
<ElInputNumber v-model="editSentence.audioPosition[1]" :precision="2" :step="0.1">
|
||||
<template #suffix>
|
||||
<span>s</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</ElInputNumber>
|
||||
<span>或</span>
|
||||
<BaseButton size="small" @click="editSentence.audioPosition[1] = -1">结束</BaseButton>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import {onMounted, onUnmounted} from "vue";
|
||||
import {Article, getDefaultArticle} from "@/types.ts";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {cloneDeep} from "@/utils";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
|
||||
import List from "@/pages/pc/components/list/List.vue";
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {Dict, DictType, getDefaultDict} from "@/types.ts";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {cloneDeep} from "@/utils";
|
||||
|
||||
import {FormInstance, FormRules} from "element-plus";
|
||||
import {ElForm,ElFormItem,ElInput,ElSelect,ElOption, FormInstance, FormRules} from "element-plus";
|
||||
import {onMounted, reactive} from "vue";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
isAdd: boolean,
|
||||
@@ -85,38 +86,38 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<div class="w-120 mt-4">
|
||||
<el-form
|
||||
<ElForm
|
||||
ref="dictFormRef"
|
||||
:rules="dictRules"
|
||||
:model="dictForm"
|
||||
label-width="8rem">
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="dictForm.name"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="描述">
|
||||
<el-input v-model="dictForm.description" type="textarea"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="原文语言">
|
||||
<el-select v-model="dictForm.language" placeholder="请选择选项">
|
||||
<el-option label="英语" value="en"/>
|
||||
<el-option label="德语" value="de"/>
|
||||
<el-option label="日语" value="ja"/>
|
||||
<el-option label="代码" value="code"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="译文语言">
|
||||
<el-select v-model="dictForm.translateLanguage" placeholder="请选择选项">
|
||||
<el-option label="中文" value="zh-CN"/>
|
||||
<el-option label="英语" value="en"/>
|
||||
<el-option label="德语" value="de"/>
|
||||
<el-option label="日语" value="ja"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<ElFormItem label="名称" prop="name">
|
||||
<ElInput v-model="dictForm.name"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="描述">
|
||||
<ElInput v-model="dictForm.description" type="textarea"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="原文语言">
|
||||
<ElSelect v-model="dictForm.language" placeholder="请选择选项">
|
||||
<ElOption label="英语" value="en"/>
|
||||
<ElOption label="德语" value="de"/>
|
||||
<ElOption label="日语" value="ja"/>
|
||||
<ElOption label="代码" value="code"/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="译文语言">
|
||||
<ElSelect v-model="dictForm.translateLanguage" placeholder="请选择选项">
|
||||
<ElOption label="中文" value="zh-CN"/>
|
||||
<ElOption label="英语" value="en"/>
|
||||
<ElOption label="德语" value="de"/>
|
||||
<ElOption label="日语" value="ja"/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<div class="center">
|
||||
<el-button @click="emit('close')">关闭</el-button>
|
||||
<el-button type="primary" @click="onSubmit">确定</el-button>
|
||||
<base-button type="info" @click="emit('close')">关闭</base-button>
|
||||
<base-button type="primary" @click="onSubmit">确定</base-button>
|
||||
</div>
|
||||
</el-form>
|
||||
</ElForm>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref, computed, watch, onMounted, nextTick} from 'vue'
|
||||
import {shuffle} from "lodash-es";
|
||||
import {computed, nextTick, onMounted, ref, watch} from 'vue'
|
||||
import {shuffle} from "@/utils";
|
||||
|
||||
const props = defineProps({
|
||||
stem: String,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import TypingArticle from "./TypingArticle.vue";
|
||||
import {Article, ArticleItem, ArticleWord, DisplayStatistics, getDefaultArticle, ShortcutKey, Word} from "@/types.ts";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {cloneDeep} from "@/utils";
|
||||
import Panel from "../../components/Panel.vue";
|
||||
import {onMounted, onUnmounted} from "vue";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
@@ -19,6 +19,7 @@ import ArticleList from "@/pages/pc/components/list/ArticleList.vue";
|
||||
import {useOnKeyboardEventListener} from "@/hooks/event.ts";
|
||||
import TranslateSetting from "@/pages/pc/components/toolbar/TranslateSetting.vue";
|
||||
import {genArticleSectionData, usePlaySentenceAudio} from "@/hooks/article.ts";
|
||||
import {ElProgress} from 'element-plus';
|
||||
|
||||
const store = useBaseStore()
|
||||
const statisticsStore = usePracticeStore()
|
||||
@@ -286,56 +287,52 @@ const {playSentenceAudio} = usePlaySentenceAudio()
|
||||
:article="articleData.article"
|
||||
/>
|
||||
|
||||
<Teleport to="body">
|
||||
<div class="panel-wrapper">
|
||||
<Panel v-if="tabIndex === 0">
|
||||
<template v-slot="{active}">
|
||||
<div class="panel-page-item">
|
||||
<div class="list-header">
|
||||
<div class="left">
|
||||
<BaseIcon title="切换词典"
|
||||
icon="carbon:change-catalog"/>
|
||||
<div class="title">
|
||||
{{ store.currentBook.name }}
|
||||
</div>
|
||||
<Tooltip
|
||||
:title="`下一章(${settingStore.shortcutKeyMap[ShortcutKey.NextChapter]})`"
|
||||
v-if="store.currentBook.lastLearnIndex < articleData.articles.length - 1">
|
||||
<IconWrapper>
|
||||
<Icon @click="emitter.emit(EventKey.continueStudy)" icon="octicon:arrow-right-24"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div class="right">
|
||||
{{ articleData.articles.length }}篇文章
|
||||
<div class="panel-wrapper">
|
||||
<Panel>
|
||||
<template v-slot="{active}">
|
||||
<div class="panel-page-item pl-4">
|
||||
<div class="list-header">
|
||||
<div class="left">
|
||||
<div class="title">
|
||||
{{ store.currentBook.name }}
|
||||
</div>
|
||||
<Tooltip
|
||||
:title="`下一篇(${settingStore.shortcutKeyMap[ShortcutKey.NextChapter]})`"
|
||||
v-if="store.currentBook.lastLearnIndex < articleData.articles.length - 1">
|
||||
<IconWrapper>
|
||||
<Icon @click="emitter.emit(EventKey.continueStudy)" icon="octicon:arrow-right-24"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div class="right">
|
||||
{{ articleData.articles.length }}篇文章
|
||||
</div>
|
||||
|
||||
<ArticleList
|
||||
:isActive="active"
|
||||
:static="false"
|
||||
:show-translate="settingStore.translate"
|
||||
@click="handleChangeChapterIndex"
|
||||
:active-id="articleData.article.id"
|
||||
:list="articleData.articles ">
|
||||
<template v-slot:suffix="{item,index}">
|
||||
<BaseIcon
|
||||
v-if="!isArticleCollect(item)"
|
||||
class="collect"
|
||||
@click="toggleArticleCollect(item)"
|
||||
title="收藏" icon="ph:star"/>
|
||||
<BaseIcon
|
||||
v-else
|
||||
class="fill"
|
||||
@click="toggleArticleCollect(item)"
|
||||
title="取消收藏" icon="ph:star-fill"/>
|
||||
</template>
|
||||
</ArticleList>
|
||||
</div>
|
||||
</template>
|
||||
</Panel>
|
||||
</div>
|
||||
</Teleport>
|
||||
|
||||
<ArticleList
|
||||
:isActive="active"
|
||||
:static="false"
|
||||
:show-translate="settingStore.translate"
|
||||
@click="handleChangeChapterIndex"
|
||||
:active-id="articleData.article.id"
|
||||
:list="articleData.articles ">
|
||||
<template v-slot:suffix="{item,index}">
|
||||
<BaseIcon
|
||||
v-if="!isArticleCollect(item)"
|
||||
class="collect"
|
||||
@click="toggleArticleCollect(item)"
|
||||
title="收藏" icon="ph:star"/>
|
||||
<BaseIcon
|
||||
v-else
|
||||
class="fill"
|
||||
@click="toggleArticleCollect(item)"
|
||||
title="取消收藏" icon="ph:star-fill"/>
|
||||
</template>
|
||||
</ArticleList>
|
||||
</div>
|
||||
</template>
|
||||
</Panel>
|
||||
</div>
|
||||
|
||||
<EditSingleArticleModal
|
||||
v-model="showEditArticle"
|
||||
@@ -345,34 +342,32 @@ const {playSentenceAudio} = usePlaySentenceAudio()
|
||||
</div>
|
||||
<div class="footer " :class="!settingStore.showToolbar && 'hide'">
|
||||
<div class="bottom">
|
||||
<div class="flex justify-between">
|
||||
<div>
|
||||
<el-progress
|
||||
class="flex-1"
|
||||
:percentage="progress"
|
||||
:stroke-width="8"
|
||||
:show-text="false"/>
|
||||
<div class="stat">
|
||||
<div class="row">
|
||||
<div class="num">{{ speedMinute }}分钟</div>
|
||||
<div class="line"></div>
|
||||
<div class="name">时间</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="num">{{ statisticsStore.total }}</div>
|
||||
<div class="line"></div>
|
||||
<div class="name">单词总数</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="num">{{ format(statisticsStore.inputWordNumber, '', 0) }}</div>
|
||||
<div class="line"></div>
|
||||
<div class="name">输入数</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="num">{{ format(statisticsStore.wrong, '', 0) }}</div>
|
||||
<div class="line"></div>
|
||||
<div class="name">错误数</div>
|
||||
</div>
|
||||
<ElProgress
|
||||
class="flex-1"
|
||||
:percentage="progress"
|
||||
:stroke-width="8"
|
||||
:show-text="false"/>
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="stat">
|
||||
<div class="row">
|
||||
<div class="num">{{ speedMinute }}分钟</div>
|
||||
<div class="line"></div>
|
||||
<div class="name">时间</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="num">{{ statisticsStore.total }}</div>
|
||||
<div class="line"></div>
|
||||
<div class="name">单词总数</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="num">{{ format(statisticsStore.inputWordNumber, '', 0) }}</div>
|
||||
<div class="line"></div>
|
||||
<div class="name">输入数</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="num">{{ format(statisticsStore.wrong, '', 0) }}</div>
|
||||
<div class="line"></div>
|
||||
<div class="name">错误数</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col items-center justify-center gap-1">
|
||||
@@ -417,7 +412,7 @@ const {playSentenceAudio} = usePlaySentenceAudio()
|
||||
</div>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<el-progress :percentage="progress"
|
||||
<ElProgress :percentage="progress"
|
||||
:stroke-width="8"
|
||||
:show-text="false"/>
|
||||
</div>
|
||||
@@ -471,12 +466,12 @@ const {playSentenceAudio} = usePlaySentenceAudio()
|
||||
}
|
||||
|
||||
.panel-wrapper {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: .6rem;
|
||||
position: absolute;
|
||||
left: var(--article-panel-margin-left);
|
||||
//left: 0;
|
||||
top: .8rem;
|
||||
z-index: 1;
|
||||
margin-left: var(--article-panel-margin-left);
|
||||
height: calc(100% - 1.2rem);
|
||||
height: calc(100% - 1.5rem);
|
||||
}
|
||||
|
||||
.footer {
|
||||
@@ -501,7 +496,7 @@ const {playSentenceAudio} = usePlaySentenceAudio()
|
||||
box-sizing: border-box;
|
||||
border-radius: .6rem;
|
||||
background: var(--color-second);
|
||||
padding: .2rem var(--space) .4rem var(--space);
|
||||
padding: .5rem var(--space);
|
||||
z-index: 2;
|
||||
border: 1px solid var(--color-item-border);
|
||||
box-shadow: var(--shadow);
|
||||
@@ -510,7 +505,7 @@ const {playSentenceAudio} = usePlaySentenceAudio()
|
||||
margin-top: .5rem;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
gap: 2rem;
|
||||
gap: var(--stat-gap);
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
@@ -538,7 +533,7 @@ const {playSentenceAudio} = usePlaySentenceAudio()
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
:deep(.el-progress-bar__inner) {
|
||||
:deep(.ElProgress-bar__inner) {
|
||||
background: var(--color-scrollbar);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,12 @@ import {Sort} from "@/types.ts";
|
||||
import MiniDialog from "@/pages/pc/components/dialog/MiniDialog.vue";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import {cloneDeep, debounce, reverse, shuffle} from "lodash-es";
|
||||
import {cloneDeep, debounce, reverse, shuffle} from "@/utils";
|
||||
import Input from "@/pages/pc/components/Input.vue";
|
||||
import PopConfirm from "@/pages/pc/components/PopConfirm.vue";
|
||||
import Empty from "@/components/Empty.vue";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import {ElCheckbox, ElPagination} from 'element-plus'
|
||||
|
||||
let list = defineModel('list')
|
||||
|
||||
@@ -117,7 +118,7 @@ const s = useSlots()
|
||||
|
||||
defineRender(
|
||||
() => {
|
||||
const d = (item) => <el-checkbox
|
||||
const d = (item) => <ElCheckbox
|
||||
modelValue={selectIds.includes(item.id)}
|
||||
onChange={() => toggleSelect(item)}
|
||||
size="large"/>
|
||||
@@ -133,14 +134,14 @@ defineRender(
|
||||
<Input
|
||||
modelValue={searchKey}
|
||||
onUpdate:modelValue=
|
||||
{debounce(e => searchKey = e)}
|
||||
{debounce(e => searchKey = e)}
|
||||
class="flex-1"/>
|
||||
<BaseButton onClick={() => (showSearchInput = false, searchKey = '')}>取消</BaseButton>
|
||||
</div>
|
||||
) : (
|
||||
<div class="flex justify-between " v-else>
|
||||
<div class="flex gap-2 items-center">
|
||||
<el-checkbox
|
||||
<ElCheckbox
|
||||
disabled={!currentList.length}
|
||||
onClick={() => toggleSelectAll()}
|
||||
modelValue={selectAll}
|
||||
@@ -219,14 +220,14 @@ defineRender(
|
||||
})}
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<el-pagination background
|
||||
currentPage={pageNo}
|
||||
onUpdate:current-page={handlePageNo}
|
||||
pageSize={pageSize}
|
||||
onUpdate:page-size={(e) => pageSize = e}
|
||||
pageSizes={[20, 50, 100, 200]}
|
||||
layout="prev, pager, next"
|
||||
total={list.value.length}/>
|
||||
<ElPagination background
|
||||
currentPage={pageNo}
|
||||
onUpdate:current-page={handlePageNo}
|
||||
pageSize={pageSize}
|
||||
onUpdate:page-size={(e) => pageSize = e}
|
||||
pageSizes={[20, 50, 100, 200]}
|
||||
layout="prev, pager, next"
|
||||
total={list.value.length}/>
|
||||
</div>
|
||||
</>
|
||||
) : <Empty/>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import {Dict} from "@/types.ts";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import {ElProgress,ElCheckbox} from 'element-plus';
|
||||
|
||||
const props = defineProps<{
|
||||
item?: Dict
|
||||
@@ -36,11 +37,11 @@ const studyProgress = $computed(() => {
|
||||
<div>{{ studyProgress }}{{ item?.length }}{{ quantifier }}</div>
|
||||
</div>
|
||||
<div class="absolute bottom-2 left-4 right-4">
|
||||
<el-progress v-if="item?.lastLearnIndex || item.complete" class="mt-1"
|
||||
<ElProgress v-if="item?.lastLearnIndex || item.complete" class="mt-1"
|
||||
:percentage="progress"
|
||||
:show-text="false"></el-progress>
|
||||
:show-text="false"></ElProgress>
|
||||
</div>
|
||||
<el-checkbox v-if="showCheckbox"
|
||||
<ElCheckbox v-if="showCheckbox"
|
||||
:model-value="checked"
|
||||
@click.stop="$emit('check')"
|
||||
class="absolute left-3 bottom-2"/>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import {ElInput} from "element-plus";
|
||||
|
||||
import {watchEffect} from "vue";
|
||||
|
||||
@@ -37,7 +38,7 @@ function toggle() {
|
||||
<div
|
||||
v-if="edit"
|
||||
class="edit-text">
|
||||
<el-input
|
||||
<ElInput
|
||||
v-model="editVal"
|
||||
ref="inputRef"
|
||||
autosize
|
||||
|
||||
@@ -20,7 +20,7 @@ $w: 1.4rem;
|
||||
transition: all .3s;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-primary);
|
||||
background: var(--color-icon-hightlight);
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import {useBaseStore} from "@/stores/base.ts"
|
||||
|
||||
import {computed, onMounted, onUnmounted, provide, watch} from "vue"
|
||||
import {computed, provide, watch} from "vue"
|
||||
import {Dict, DictType, ShortcutKey} from "@/types.ts"
|
||||
import PopConfirm from "@/pages/pc/components/PopConfirm.vue"
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
@@ -9,18 +9,14 @@ import {useSettingStore} from "@/stores/setting.ts";
|
||||
import Close from "@/components/icon/Close.vue";
|
||||
import Empty from "@/components/Empty.vue";
|
||||
import {useArticleOptions, useWordOptions} from "@/hooks/dict.ts";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import Tooltip from "@/pages/pc/components/Tooltip.vue";
|
||||
import IconWrapper from "@/pages/pc/components/IconWrapper.vue";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import {emitter, EventKey, useEvent} from "@/utils/eventBus.ts";
|
||||
import {useRouter} from "vue-router";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {useNav} from "@/utils";
|
||||
import WordList from "@/pages/pc/components/list/WordList.vue";
|
||||
import ArticleList from "@/pages/pc/components/list/ArticleList.vue";
|
||||
import Slide from "@/pages/pc/components/Slide.vue";
|
||||
import {useNav} from "@/utils";
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
type?: DictType
|
||||
|
||||
@@ -1,644 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import {Icon} from '@iconify/vue';
|
||||
import {ref, watch} from "vue";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {getAudioFileUrl, useChangeAllSound, usePlayAudio, useWatchAllSound} from "@/hooks/sound.ts";
|
||||
import {getShortcutKey, useDisableEventListener, useEventListener} from "@/hooks/event.ts";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {DefaultShortcutKeyMap, ShortcutKey} from "@/types.ts";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import {APP_NAME, EXPORT_DATA_KEY, 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 {checkAndUpgradeSaveDict, checkAndUpgradeSaveSetting, shakeCommonDict} from "@/utils";
|
||||
import {GITHUB} from "@/config/ENV.ts";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
|
||||
const emit = defineEmits<{
|
||||
toggleDisabledDialogEscKey: [val: boolean]
|
||||
}>()
|
||||
|
||||
const tabIndex = $ref(0)
|
||||
const settingStore = useSettingStore()
|
||||
const store = useBaseStore()
|
||||
//@ts-ignore
|
||||
const gitLastCommitHash = ref(LATEST_COMMIT_HASH);
|
||||
|
||||
useDisableEventListener(() => undefined)
|
||||
useWatchAllSound()
|
||||
|
||||
let editShortcutKey = $ref('')
|
||||
|
||||
const disabledDefaultKeyboardEvent = $computed(() => {
|
||||
return editShortcutKey && tabIndex === 2
|
||||
})
|
||||
|
||||
watch(() => disabledDefaultKeyboardEvent, v => {
|
||||
emit('toggleDisabledDialogEscKey', !!v)
|
||||
})
|
||||
|
||||
useEventListener('keydown', (e: KeyboardEvent) => {
|
||||
if (!disabledDefaultKeyboardEvent) return
|
||||
e.preventDefault()
|
||||
|
||||
let shortcutKey = getShortcutKey(e)
|
||||
// console.log('e', e, e.keyCode, e.ctrlKey, e.altKey, e.shiftKey)
|
||||
// console.log('key', shortcutKey)
|
||||
|
||||
// if (shortcutKey[shortcutKey.length-1] === '+') {
|
||||
// settingStore.shortcutKeyMap[editShortcutKey] = DefaultShortcutKeyMap[editShortcutKey]
|
||||
// return ElMessage.warning('设备失败!')
|
||||
// }
|
||||
|
||||
if (editShortcutKey) {
|
||||
if (shortcutKey === 'Delete') {
|
||||
settingStore.shortcutKeyMap[editShortcutKey] = ''
|
||||
} else {
|
||||
for (const [k, v] of Object.entries(settingStore.shortcutKeyMap)) {
|
||||
if (v === shortcutKey && k !== editShortcutKey) {
|
||||
settingStore.shortcutKeyMap[editShortcutKey] = DefaultShortcutKeyMap[editShortcutKey]
|
||||
return ElMessage.warning('快捷键重复!')
|
||||
}
|
||||
}
|
||||
settingStore.shortcutKeyMap[editShortcutKey] = shortcutKey
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function resetShortcutKeyMap() {
|
||||
editShortcutKey = ''
|
||||
settingStore.shortcutKeyMap = cloneDeep(DefaultShortcutKeyMap)
|
||||
ElMessage.success('恢复成功')
|
||||
}
|
||||
|
||||
function exportData() {
|
||||
let data = {
|
||||
version: EXPORT_DATA_KEY.version,
|
||||
val: {
|
||||
setting: {
|
||||
version: SAVE_SETTING_KEY.version,
|
||||
val: settingStore.$state
|
||||
},
|
||||
dict: {
|
||||
version: SAVE_DICT_KEY.version,
|
||||
val: shakeCommonDict(store.$state)
|
||||
}
|
||||
}
|
||||
}
|
||||
let blob = new Blob([JSON.stringify(data)], {type: "text/plain;charset=utf-8"});
|
||||
saveAs(blob, `${APP_NAME}-User-Data-${dayjs().format('YYYY-MM-DD HH-mm-ss')}.json`);
|
||||
ElMessage.success('导出成功!')
|
||||
}
|
||||
|
||||
function importData(e) {
|
||||
let file = e.target.files[0]
|
||||
if (!file) return
|
||||
// no()
|
||||
let reader = new FileReader();
|
||||
reader.onload = function (v) {
|
||||
let str: any = v.target.result;
|
||||
if (str) {
|
||||
let obj = {
|
||||
version: -1,
|
||||
val: {
|
||||
setting: {},
|
||||
dict: {},
|
||||
}
|
||||
}
|
||||
try {
|
||||
obj = JSON.parse(str)
|
||||
} catch (err) {
|
||||
ElMessage.error('导入失败!')
|
||||
}
|
||||
if (obj.version === EXPORT_DATA_KEY.version) {
|
||||
|
||||
} else {
|
||||
//TODO
|
||||
}
|
||||
let data = obj.val
|
||||
let settingState = checkAndUpgradeSaveSetting(data.setting)
|
||||
settingStore.setState(settingState)
|
||||
let dictState = checkAndUpgradeSaveDict(data.dict)
|
||||
store.init(dictState)
|
||||
ElMessage.success('导入成功!')
|
||||
}
|
||||
}
|
||||
reader.readAsText(file);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="setting">
|
||||
<div class="left">
|
||||
<div class="tabs">
|
||||
<div class="tab" :class="tabIndex === 0 && 'active'" @click="tabIndex = 0">
|
||||
<Icon icon="bx:headphone" width="20" color="#0C8CE9"/>
|
||||
<span>音效设置</span>
|
||||
</div>
|
||||
<div class="tab" :class="tabIndex === 2 && 'active'" @click="tabIndex = 2">
|
||||
<Icon icon="material-symbols:keyboard-outline" width="20" color="#0C8CE9"/>
|
||||
<span>快捷键设置</span>
|
||||
</div>
|
||||
<div class="tab" :class="tabIndex === 1 && 'active'" @click="tabIndex = 1">
|
||||
<Icon icon="icon-park-outline:setting-config" width="20" color="#0C8CE9"/>
|
||||
<span>其他设置</span>
|
||||
</div>
|
||||
<div class="tab" :class="tabIndex === 3 && 'active'" @click="tabIndex = 3">
|
||||
<Icon icon="mdi:database-cog-outline" width="20" color="#0C8CE9"/>
|
||||
<span>数据管理</span>
|
||||
</div>
|
||||
<div class="tab" :class="tabIndex === 4 && 'active'" @click="tabIndex = 4">
|
||||
<Icon icon="mingcute:service-fill" width="20" color="#0C8CE9"/>
|
||||
<span>反馈</span>
|
||||
</div>
|
||||
<div class="tab" :class="tabIndex === 5 && 'active'" @click="tabIndex = 5">
|
||||
<Icon icon="mdi:about-circle-outline" width="20" color="#0C8CE9"/>
|
||||
<span>关于</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="git-log">
|
||||
Build {{ gitLastCommitHash }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div v-if="tabIndex === 0">
|
||||
<div class="row">
|
||||
<label class="main-title">所有音效</label>
|
||||
<div class="wrapper">
|
||||
<el-switch v-model="settingStore.allSound"
|
||||
@change="useChangeAllSound"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="row">
|
||||
<label class="item-title">单词/句子自动发音</label>
|
||||
<div class="wrapper">
|
||||
<el-switch v-model="settingStore.wordSound"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="sub-title">单词/句子发音口音</label>
|
||||
<div class="wrapper">
|
||||
<el-select v-model="settingStore.wordSoundType"
|
||||
placeholder="请选择"
|
||||
>
|
||||
<el-option label="美音" value="us"/>
|
||||
<el-option label="英音" value="uk"/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="sub-title">音量</label>
|
||||
<div class="wrapper">
|
||||
<el-slider v-model="settingStore.wordSoundVolume"/>
|
||||
<span>{{ settingStore.wordSoundVolume }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="sub-title">倍速</label>
|
||||
<div class="wrapper">
|
||||
<el-slider v-model="settingStore.wordSoundSpeed" :step="0.1" :min="0.5" :max="3"/>
|
||||
<span>{{ settingStore.wordSoundSpeed }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="row">
|
||||
<label class="item-title">按键音</label>
|
||||
<div class="wrapper">
|
||||
<el-switch v-model="settingStore.keyboardSound"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="item-title">按键音效</label>
|
||||
<div class="wrapper">
|
||||
<el-select v-model="settingStore.keyboardSoundFile"
|
||||
placeholder="请选择"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in SoundFileOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
<div class="el-option-row">
|
||||
<span>{{ item.label }}</span>
|
||||
<VolumeIcon
|
||||
:time="100"
|
||||
@click="usePlayAudio(getAudioFileUrl(item.value)[0])"/>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="sub-title">音量</label>
|
||||
<div class="wrapper">
|
||||
<el-slider v-model="settingStore.keyboardSoundVolume"/>
|
||||
<span>{{ settingStore.keyboardSoundVolume }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="row">
|
||||
<label class="item-title">效果音(输入错误、完成时的音效)</label>
|
||||
<div class="wrapper">
|
||||
<el-switch v-model="settingStore.effectSound"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="sub-title">音量</label>
|
||||
<div class="wrapper">
|
||||
<el-slider v-model="settingStore.effectSoundVolume"/>
|
||||
<span>{{ settingStore.effectSoundVolume }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="tabIndex === 1">
|
||||
<div class="row">
|
||||
<label class="item-title">显示上一个/下一个单词</label>
|
||||
<div class="wrapper">
|
||||
<el-switch v-model="settingStore.showNearWord"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="desc">
|
||||
开启后,练习中会在上方显示上一个/下一个单词
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="row">
|
||||
<label class="item-title">忽略大小写</label>
|
||||
<div class="wrapper">
|
||||
<el-switch v-model="settingStore.ignoreCase"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="desc">
|
||||
开启后,输入时不区分大小写,如输入“hello”和“Hello”都会被认为是正确的
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="row">
|
||||
<label class="item-title">允许默写模式下显示提示</label>
|
||||
<div class="wrapper">
|
||||
<el-switch v-model="settingStore.allowWordTip"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="desc">
|
||||
开启后,可以通过鼠标 hover 单词或者按 {{ settingStore.shortcutKeyMap[ShortcutKey.ShowWord] }} 显示正确答案
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="row">
|
||||
<label class="item-title">字体设置(仅可调整单词练习)</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="sub-title">外语字体</label>
|
||||
<div class="wrapper">
|
||||
<el-slider
|
||||
:min="10"
|
||||
:max="100"
|
||||
v-model="settingStore.fontSize.wordForeignFontSize"/>
|
||||
<span>{{ settingStore.fontSize.wordForeignFontSize }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="sub-title">中文字体</label>
|
||||
<div class="wrapper">
|
||||
<el-slider
|
||||
:min="10"
|
||||
:max="100"
|
||||
v-model="settingStore.fontSize.wordTranslateFontSize"/>
|
||||
<span>{{ settingStore.fontSize.wordTranslateFontSize }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="line"></div>
|
||||
<div class="row">
|
||||
<label class="item-title">其他设置</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="sub-title">切换下一个单词时间</label>
|
||||
<div class="wrapper">
|
||||
<el-input-number v-model="settingStore.waitTimeForChangeWord"
|
||||
:min="6"
|
||||
:max="100"
|
||||
type="number"
|
||||
/>
|
||||
<span>毫秒</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="body" v-if="tabIndex === 2">
|
||||
<div class="row">
|
||||
<label class="main-title">功能</label>
|
||||
<div class="wrapper">快捷键(点击可修改)</div>
|
||||
</div>
|
||||
<div class="scroll">
|
||||
<div class="row" v-for="item of Object.entries(settingStore.shortcutKeyMap)">
|
||||
<label class="item-title">{{ $t(item[0]) }}</label>
|
||||
<div class="wrapper" @click="editShortcutKey = item[0]">
|
||||
<div class="set-key" v-if="editShortcutKey === item[0]">
|
||||
<input :value="item[1]?item[1]:'未设置快捷键'" readonly type="text" @blur="editShortcutKey = ''">
|
||||
<span @click.stop="editShortcutKey = ''">直接按键盘进行设置</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div v-if="item[1]">{{ item[1] }}</div>
|
||||
<span v-else>未设置快捷键</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row footer">
|
||||
<label class="item-title"></label>
|
||||
<div class="wrapper">
|
||||
<BaseButton @click="resetShortcutKeyMap">恢复默认</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="tabIndex === 3">
|
||||
<div class="row">
|
||||
<div class="main-title">数据导出</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="sub-title">
|
||||
目前用户的所有数据(自定义设置、自定义词典、练习进度等)
|
||||
<b>仅保存在本地</b>
|
||||
。如果您需要在不同的设备、浏览器或者其他非官方部署上使用 {{ APP_NAME }}, 您需要手动进行数据同步和保存。
|
||||
</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<BaseButton @click="exportData">数据导出</BaseButton>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="main-title">数据导入</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="sub-title">
|
||||
请注意,导入数据将
|
||||
<b style="color: red"> 完全覆盖 </b>
|
||||
当前数据。请谨慎操作。
|
||||
</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="import hvr-grow">
|
||||
<BaseButton>数据导入</BaseButton>
|
||||
<input type="file"
|
||||
accept="application/json"
|
||||
@change="importData">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="tabIndex === 4" class="feedback-modal">
|
||||
<div>
|
||||
给我发Email:<a href="mailto:zyronon@163.com">zyronon@163.com</a>
|
||||
</div>
|
||||
<p>or</p>
|
||||
<div class="github">
|
||||
<span>在<a :href="GITHUB" target="_blank">Github</a>上给我提一个
|
||||
<a :href="`${GITHUB}/issues`" target="_blank">Issue</a>
|
||||
</span>
|
||||
<div class="options">
|
||||
<BaseButton>
|
||||
<a :href="`${GITHUB}/issues/new?assignees=&labels=&projects=&template=%E5%8D%95%E8%AF%8D%E9%94%99%E8%AF%AF---word-error.md&title=%E5%8D%95%E8%AF%8D%E9%94%99%E8%AF%AF+%7C+Word+error`"
|
||||
target="_blank">词典错误?</a>
|
||||
</BaseButton>
|
||||
<BaseButton>
|
||||
<a :href="`${GITHUB}/issues/new?assignees=&labels=&projects=&template=问题报告---bug-report-.md&title=问题报告+%7C+Bug+report+`"
|
||||
target="_blank">反馈BUG?</a>
|
||||
</BaseButton>
|
||||
<BaseButton>
|
||||
<a :href="`${GITHUB}/issues/new?assignees=&labels=&projects=&template=功能请求---feature-request.md&title=功能请求+%7C+Feature+request`"
|
||||
target="_blank">功能请求?</a>
|
||||
</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="tabIndex === 5" class="about">
|
||||
<h1>Type Words</h1>
|
||||
<p>
|
||||
本项目完全开源!好用请大家多多点Star!
|
||||
</p>
|
||||
<p>
|
||||
GitHub地址:<a href="https://github.com/zyronon/typing-word">https://github.com/zyronon/typing-word</a>
|
||||
</p>
|
||||
<p>
|
||||
反馈:<a href="https://github.com/zyronon/typing-word/issues">https://github.com/zyronon/typing-word/issues</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
|
||||
.setting {
|
||||
width: 40vw;
|
||||
height: 70vh;
|
||||
display: flex;
|
||||
color: var(--color-font-1);
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.tabs {
|
||||
padding: .6rem 1.6rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
//align-items: center;
|
||||
//justify-content: center;
|
||||
gap: .6rem;
|
||||
|
||||
.tab {
|
||||
cursor: pointer;
|
||||
padding: .6rem .9rem;
|
||||
border-radius: .5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: .6rem;
|
||||
|
||||
&.active {
|
||||
background: var(--color-item-bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.git-log {
|
||||
font-size: .6rem;
|
||||
color: gray;
|
||||
margin-bottom: .3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding: 0 var(--space);
|
||||
|
||||
.row {
|
||||
min-height: 2.6rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: calc(var(--space) * 5);
|
||||
|
||||
.wrapper {
|
||||
height: 2rem;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: var(--space);
|
||||
|
||||
span {
|
||||
text-align: right;
|
||||
//width: 30rem;
|
||||
font-size: .7rem;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.set-key {
|
||||
align-items: center;
|
||||
|
||||
input {
|
||||
width: 9rem;
|
||||
box-sizing: border-box;
|
||||
margin-right: .6rem;
|
||||
height: 1.8rem;
|
||||
outline: none;
|
||||
font-size: 1rem;
|
||||
border: 1px solid gray;
|
||||
border-radius: .2rem;
|
||||
padding: 0 .3rem;
|
||||
background: var(--color-second);
|
||||
color: var(--color-font-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.main-title {
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.sub-title {
|
||||
font-size: .9rem;
|
||||
}
|
||||
}
|
||||
|
||||
.body {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.scroll {
|
||||
flex: 1;
|
||||
padding-right: .6rem;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-bottom: 1.3rem;
|
||||
}
|
||||
|
||||
.desc {
|
||||
margin-bottom: .6rem;
|
||||
font-size: .8rem;
|
||||
}
|
||||
|
||||
.line {
|
||||
border-bottom: 1px solid #c4c3c3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-option-row {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.icon-wrapper {
|
||||
transform: translateX(10rem);
|
||||
}
|
||||
}
|
||||
|
||||
.import {
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
|
||||
input {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.feedback-modal {
|
||||
//height: 80vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: var(--space);
|
||||
//justify-content: center;
|
||||
color: var(--color-font-1);
|
||||
|
||||
p {
|
||||
font-size: 2.4rem;
|
||||
}
|
||||
|
||||
.github {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space);
|
||||
|
||||
.options {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .6rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.about {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -3,6 +3,7 @@
|
||||
import {Word} from "@/types.ts";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
import {usePlayWordAudio} from "@/hooks/sound.ts";
|
||||
import {ElPopover} from 'element-plus'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
item: Word,
|
||||
@@ -35,7 +36,7 @@ const playWordAudio = usePlayWordAudio()
|
||||
</div>
|
||||
<div class="item-sub-title flex flex-col gap-2" v-if="item.trans.length && showTranslate">
|
||||
<div v-for="v in item.trans">
|
||||
<el-popover
|
||||
<ElPopover
|
||||
v-if="v.cn.length > 30 && showTransPop"
|
||||
width="300"
|
||||
:content="v.pos + ' ' + v.cn"
|
||||
@@ -44,7 +45,7 @@ const playWordAudio = usePlayWordAudio()
|
||||
<template #reference>
|
||||
<span>{{ v.pos + ' ' + v.cn.slice(0, 30) + '...' }}</span>
|
||||
</template>
|
||||
</el-popover>
|
||||
</ElPopover>
|
||||
<span v-else>{{ v.pos + ' ' + v.cn }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import Input from "@/pages/pc/components/Input.vue";
|
||||
import {cloneDeep, throttle} from "lodash-es";
|
||||
import {cloneDeep, throttle} from "@/utils";
|
||||
import {Article} from "@/types.ts";
|
||||
|
||||
interface IProps {
|
||||
|
||||
@@ -4,6 +4,7 @@ import {Word} from "@/types.ts";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
import BaseList from "@/pages/pc/components/list/BaseList.vue";
|
||||
import {usePlayWordAudio} from "@/hooks/sound.ts";
|
||||
import {ElPopover} from 'element-plus'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
list: Word[],
|
||||
@@ -53,7 +54,7 @@ defineExpose({scrollToBottom, scrollToItem})
|
||||
</div>
|
||||
<div class="item-sub-title flex flex-col gap-2" v-if="item.trans.length && showTranslate">
|
||||
<div v-for="v in item.trans">
|
||||
<el-popover
|
||||
<ElPopover
|
||||
v-if="v.cn.length > 30"
|
||||
width="300"
|
||||
:content="v.pos + ' ' + v.cn"
|
||||
@@ -62,7 +63,7 @@ defineExpose({scrollToBottom, scrollToItem})
|
||||
<template #reference>
|
||||
<span>{{ v.pos + ' ' + v.cn.slice(0, 30) + '...' }}</span>
|
||||
</template>
|
||||
</el-popover>
|
||||
</ElPopover>
|
||||
<span v-else>{{ v.pos + ' ' + v.cn }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,11 +6,10 @@ import IconWrapper from "@/pages/pc/components/IconWrapper.vue";
|
||||
import Tooltip from "@/pages/pc/components/Tooltip.vue";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import {useWindowClick} from "@/hooks/event.ts";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import Dialog from "@/pages/pc/components/dialog/Dialog.vue";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {ShortcutKey} from "@/types.ts";
|
||||
import {ElSwitch, ElRadioGroup,ElRadioButton,ElSelect,ElOption} from 'element-plus'
|
||||
|
||||
const store = useBaseStore()
|
||||
const settingStore = useSettingStore()
|
||||
@@ -59,19 +58,19 @@ function save() {
|
||||
<div class="mini-row">
|
||||
<label class="item-title">显示翻译</label>
|
||||
<div class="wrapper">
|
||||
<el-switch v-model="settingStore.translate"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
<ElSwitch v-model="settingStore.translate"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mini-row">
|
||||
<label class="item-title">翻译类型</label>
|
||||
<el-radio-group v-model="translateType" size="small">
|
||||
<el-radio-button :value="1">本地翻译</el-radio-button>
|
||||
<el-radio-button :value="0">网络翻译</el-radio-button>
|
||||
</el-radio-group>
|
||||
<ElRadioGroup v-model="translateType" size="small">
|
||||
<ElRadioButton :value="1">本地翻译</ElRadioButton>
|
||||
<ElRadioButton :value="0">网络翻译</ElRadioButton>
|
||||
</ElRadioGroup>
|
||||
</div>
|
||||
<div class="mini-row" v-if="translateType">
|
||||
<label class="item-title">本地翻译</label>
|
||||
@@ -88,14 +87,14 @@ function save() {
|
||||
<div class="mini-row" v-else>
|
||||
<label class="item-title">网络翻译</label>
|
||||
<div class="wrapper">
|
||||
<el-select v-model="networkTranslateEngine" class="m-2" placeholder="Select" size="small">
|
||||
<el-option
|
||||
<ElSelect v-model="networkTranslateEngine" class="m-2" placeholder="Select" size="small">
|
||||
<ElOption
|
||||
v-for="item in TranslateEngine"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</ElSelect>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import {splitEnArticle2} from "@/hooks/article.ts";
|
||||
import test from '../../test/test.vue'
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
|
||||
function test1() {
|
||||
splitEnArticle2(
|
||||
@@ -19,8 +20,8 @@ function test2() {
|
||||
|
||||
<template>
|
||||
<div class="word flex center h-screen ">
|
||||
<El-Button @click="test1">test1</El-Button>
|
||||
<El-Button @click="test2">test2</El-Button>
|
||||
<base-button @click="test1">test1</base-button>
|
||||
<base-button @click="test2">test2</base-button>
|
||||
<test/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -99,7 +99,7 @@ const {toggleTheme} = useTheme()
|
||||
flex-shrink: 0;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-primary);
|
||||
background: var(--color-select-bg);
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import {DictId, getDefaultDict} from "@/types";
|
||||
import BasePage from "@/pages/pc/components/BasePage.vue";
|
||||
import {computed, onMounted, reactive} from "vue";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {assign, cloneDeep} from "lodash-es";
|
||||
import {assign, cloneDeep} from "@/utils";
|
||||
import {nanoid} from "nanoid";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import BaseTable from "@/pages/pc/components/BaseTable.vue";
|
||||
@@ -18,6 +18,7 @@ import {useRoute, useRouter} from "vue-router";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import EditBook from "@/pages/pc/article/components/EditBook.vue";
|
||||
import {_getDictDataByUrl, _nextTick, convertToWord} from "@/utils";
|
||||
import {ElForm, ElFormItem, ElInput, ElMessage} from "element-plus";
|
||||
|
||||
const runtimeStore = useRuntimeStore()
|
||||
const base = useBaseStore()
|
||||
@@ -261,85 +262,86 @@ defineRender(() => {
|
||||
<div class="common-title">
|
||||
{wordForm.id ? '修改' : '添加'}单词
|
||||
</div>
|
||||
<el-form
|
||||
<ElForm
|
||||
class="flex-1 overflow-auto pr-2"
|
||||
ref={e => wordFormRef = e}
|
||||
rules={wordRules}
|
||||
model={wordForm}
|
||||
label-width="7rem">
|
||||
<el-form-item label="单词" prop="word">
|
||||
<el-input
|
||||
<ElFormItem label="单词" prop="word">
|
||||
<ElInput
|
||||
modelValue={wordForm.word}
|
||||
onUpdate:modelValue={e => wordForm.word = e}
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="英音音标">
|
||||
<el-input
|
||||
</ElFormItem>
|
||||
<ElFormItem label="英音音标">
|
||||
<ElInput
|
||||
modelValue={wordForm.phonetic0}
|
||||
onUpdate:modelValue={e => wordForm.phonetic0 = e}
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="美音音标">
|
||||
<el-input
|
||||
</ElFormItem>
|
||||
<ElFormItem label="美音音标">
|
||||
<ElInput
|
||||
modelValue={wordForm.phonetic1}
|
||||
onUpdate:modelValue={e => wordForm.phonetic1 = e}/>
|
||||
</el-form-item>
|
||||
<el-form-item label="翻译">
|
||||
<el-input
|
||||
</ElFormItem>
|
||||
<ElFormItem label="翻译">
|
||||
<ElInput
|
||||
modelValue={wordForm.trans}
|
||||
onUpdate:modelValue={e => wordForm.trans = e}
|
||||
placeholder="一行一个翻译,前面词性,后面内容(如n.取消);多个翻译请换行"
|
||||
autosize={{minRows: 6, maxRows: 10}}
|
||||
type="textarea"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="例句">
|
||||
<el-input
|
||||
</ElFormItem>
|
||||
<ElFormItem label="例句">
|
||||
<ElInput
|
||||
modelValue={wordForm.sentences}
|
||||
onUpdate:modelValue={e => wordForm.sentences = e}
|
||||
placeholder="一行原文,一行译文;多个请换两行"
|
||||
autosize={{minRows: 6, maxRows: 10}}
|
||||
type="textarea"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="短语">
|
||||
<el-input
|
||||
</ElFormItem>
|
||||
<ElFormItem label="短语">
|
||||
<ElInput
|
||||
modelValue={wordForm.phrases}
|
||||
onUpdate:modelValue={e => wordForm.phrases = e}
|
||||
placeholder="一行原文,一行译文;多个请换两行"
|
||||
autosize={{minRows: 6, maxRows: 10}}
|
||||
type="textarea"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="同义词">
|
||||
<el-input
|
||||
</ElFormItem>
|
||||
<ElFormItem label="同义词">
|
||||
<ElInput
|
||||
modelValue={wordForm.synos}
|
||||
onUpdate:modelValue={e => wordForm.synos = e}
|
||||
placeholder="请参考已有单词格式"
|
||||
autosize={{minRows: 6, maxRows: 20}}
|
||||
type="textarea"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="同根词">
|
||||
<el-input
|
||||
</ElFormItem>
|
||||
<ElFormItem label="同根词">
|
||||
<ElInput
|
||||
modelValue={wordForm.relWords}
|
||||
onUpdate:modelValue={e => wordForm.relWords = e}
|
||||
placeholder="请参考已有单词格式"
|
||||
autosize={{minRows: 6, maxRows: 20}}
|
||||
type="textarea"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="词源">
|
||||
<el-input
|
||||
</ElFormItem>
|
||||
<ElFormItem label="词源">
|
||||
<ElInput
|
||||
modelValue={wordForm.etymology}
|
||||
onUpdate:modelValue={e => wordForm.etymology = e}
|
||||
placeholder="请参考已有单词格式"
|
||||
autosize={{minRows: 6, maxRows: 10}}
|
||||
type="textarea"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<div class="center">
|
||||
<el-button
|
||||
<base-button
|
||||
type="info"
|
||||
onClick={closeWordForm}>关闭
|
||||
</el-button>
|
||||
<el-button type="primary"
|
||||
onClick={onSubmitWord}>保存
|
||||
</el-button>
|
||||
</base-button>
|
||||
<base-button type="primary"
|
||||
onClick={onSubmitWord}>保存
|
||||
</base-button>
|
||||
</div>
|
||||
</div>
|
||||
) : null
|
||||
|
||||
@@ -13,7 +13,7 @@ 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 {groupBy} from "lodash-es";
|
||||
import {groupBy} from "@/utils";
|
||||
import {dictionaryResources} from "@/assets/dictionary.ts";
|
||||
import {computed} from "vue";
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import {getDefaultWord, ShortcutKey, StudyData, Word} from "@/types.ts";
|
||||
import {useOnKeyboardEventListener, useStartKeyboardEventListener} from "@/hooks/event.ts";
|
||||
import useTheme from "@/hooks/theme.ts";
|
||||
import {getCurrentStudyWord, useWordOptions} from "@/hooks/dict.ts";
|
||||
import {cloneDeep, shuffle} from "lodash-es";
|
||||
import {_getDictDataByUrl, cloneDeep, shuffle} from "@/utils";
|
||||
import {useRoute, useRouter} from "vue-router";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import Footer from "@/pages/pc/word/components/Footer.vue";
|
||||
@@ -23,7 +23,6 @@ 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 {_getDictDataByUrl} from "@/utils";
|
||||
|
||||
interface IProps {
|
||||
new: Word[],
|
||||
|
||||
@@ -14,7 +14,8 @@ import {getCurrentStudyWord} from "@/hooks/dict.ts";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import Book from "@/pages/pc/components/Book.vue";
|
||||
import PopConfirm from "@/pages/pc/components/PopConfirm.vue";
|
||||
import {ElMessage} from 'element-plus';
|
||||
import {ElMessage, ElProgress, ElSlider} from 'element-plus';
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
|
||||
const store = useBaseStore()
|
||||
const router = useRouter()
|
||||
@@ -184,7 +185,7 @@ const progressTextRight = $computed(() => {
|
||||
<span>{{ progressTextLeft }}</span>
|
||||
<span>{{ progressTextRight }} / {{ store.sdict.words.length }}</span>
|
||||
</div>
|
||||
<el-progress class="mt-1" :percentage="store.currentStudyProgress" :show-text="false"></el-progress>
|
||||
<ElProgress class="mt-1" :percentage="store.currentStudyProgress" :show-text="false"></ElProgress>
|
||||
</div>
|
||||
<div class="text-sm text-align-end">
|
||||
预计完成日期:{{ _getAccomplishDate(store.sdict.words.length, store.sdict.perDayStudyNumber) }}
|
||||
@@ -219,12 +220,12 @@ const progressTextRight = $computed(() => {
|
||||
</div>
|
||||
个单词 <span class="color-blue cursor-pointer" @click="setPerDayStudyNumber">更改</span>
|
||||
</div>
|
||||
<div class="btn">开始学习</div>
|
||||
<div class="rounded-xl bg-slate-800 flex items-center gap-2 py-3 px-5 text-white cursor-pointer"
|
||||
:class="store.sdict.name || 'opacity-70 cursor-not-allowed'" @click="startStudy">
|
||||
<span>开始学习</span>
|
||||
<Icon icon="icons8:right-round" class="text-2xl"/>
|
||||
</div>
|
||||
<BaseButton :disabled="!store.sdict.name" @click="startStudy">
|
||||
<div class="flex items-center gap-2">
|
||||
<span>开始学习</span>
|
||||
<Icon icon="icons8:right-round" class="text-2xl"/>
|
||||
</div>
|
||||
</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -278,8 +279,8 @@ const progressTextRight = $computed(() => {
|
||||
<div class="center text-sm" :style="{ opacity: tempPerDayStudyNumber === 20 ? 1 : 0 }">
|
||||
推荐
|
||||
</div>
|
||||
<el-slider :min="10" :step="10" show-stops :marks="{ 10: '10', 200: '200' }" size="small" class="my-6"
|
||||
:max="200" v-model="tempPerDayStudyNumber"/>
|
||||
<ElSlider :min="10" :step="10" show-stops :marks="{ 10: '10', 200: '200' }" size="small" class="my-6"
|
||||
:max="200" v-model="tempPerDayStudyNumber"/>
|
||||
<div class="flex gap-2 mb-2 mt-10 items-center">
|
||||
<div>预计</div>
|
||||
<span class="text-2xl" style="color:rgb(176,116,211)">{{
|
||||
|
||||
@@ -9,6 +9,7 @@ import {Icon} from "@iconify/vue";
|
||||
import IconWrapper from "@/pages/pc/components/IconWrapper.vue";
|
||||
import Tooltip from "@/pages/pc/components/Tooltip.vue";
|
||||
import TranslateSetting from "@/pages/pc/components/toolbar/TranslateSetting.vue";
|
||||
import {ElProgress} from 'element-plus';
|
||||
|
||||
const statisticsStore = usePracticeStore()
|
||||
const settingStore = useSettingStore()
|
||||
@@ -85,7 +86,7 @@ const progress = $computed(() => {
|
||||
</Tooltip>
|
||||
|
||||
<div class="bottom">
|
||||
<el-progress
|
||||
<ElProgress
|
||||
:percentage="progress"
|
||||
:stroke-width="8"
|
||||
:show-text="false"/>
|
||||
@@ -171,7 +172,7 @@ const progress = $computed(() => {
|
||||
</div>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<el-progress :percentage="progress"
|
||||
<ElProgress :percentage="progress"
|
||||
:stroke-width="8"
|
||||
:show-text="false"/>
|
||||
</div>
|
||||
|
||||
@@ -42,6 +42,6 @@ function escapeRegExp(string: string): string {
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.highlight-word) {
|
||||
color: var(--color-primary);
|
||||
color: var(--color-icon-hightlight);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -323,7 +323,7 @@ function mouseleave() {
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
border-bottom: 2px solid var(--color-font-1);
|
||||
border-bottom: 2px solid var(--color-font-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
// import origin from './data.json'
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import {checkAndUpgradeSaveDict, shakeCommonDict} from "@/utils";
|
||||
import {checkAndUpgradeSaveDict} from "@/utils";
|
||||
import localforage from "localforage";
|
||||
import {SAVE_DICT_KEY} from "@/utils/const.ts";
|
||||
import str from './data.json'
|
||||
import {ElTableV2} from 'element-plus'
|
||||
|
||||
let data = {}
|
||||
let origin = {}
|
||||
@@ -73,7 +74,7 @@ const data1 = generateData(columns, 1000)
|
||||
<BaseButton @click="set">设置data.json的数据到localforage</BaseButton>
|
||||
<BaseButton @click="check">检测升级逻辑</BaseButton>
|
||||
</div>
|
||||
<el-table-v2
|
||||
<ElTableV2
|
||||
:columns="columns"
|
||||
:data="data1"
|
||||
:width="700"
|
||||
|
||||
@@ -52,7 +52,8 @@ export const routes: RouteRecordRaw[] = [
|
||||
]
|
||||
|
||||
const router = VueRouter.createRouter({
|
||||
history: VueRouter.createWebHistory(),
|
||||
// history: VueRouter.createWebHistory(),
|
||||
history: VueRouter.createWebHashHistory(),
|
||||
routes,
|
||||
scrollBehavior(to, from, savedPosition) {
|
||||
// console.log('savedPosition', savedPosition)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {defineStore} from 'pinia'
|
||||
import {Dict, DictId, getDefaultDict, Word} from "../types.ts"
|
||||
import {cloneDeep, merge} from "lodash-es";
|
||||
import {cloneDeep} from "@/utils";
|
||||
import * as localforage from "localforage";
|
||||
import {nanoid} from "nanoid";
|
||||
import {SAVE_DICT_KEY} from "@/utils/const.ts";
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import {defineStore} from "pinia"
|
||||
import {cloneDeep, merge} from "lodash-es";
|
||||
import {checkAndUpgradeSaveSetting, cloneDeep} from "@/utils";
|
||||
import {DefaultShortcutKeyMap} from "@/types.ts";
|
||||
import {SAVE_SETTING_KEY} from "@/utils/const.ts";
|
||||
import {checkAndUpgradeSaveDict, checkAndUpgradeSaveSetting} from "@/utils";
|
||||
|
||||
export interface SettingState {
|
||||
showToolbar: boolean,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {Dict, DictResource, getDefaultDict} from "@/types.ts";
|
||||
import {getDictFile} from "@/utils/index.ts";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {cloneDeep} from "@/utils";
|
||||
import {nanoid} from "nanoid";
|
||||
|
||||
export async function getArticleBookDataByUrl(val: DictResource) {
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
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 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),
|
||||
// )
|
||||
|
||||
// respone 拦截器
|
||||
// instance.interceptors.response.use(
|
||||
@@ -111,4 +111,4 @@ axiosInstance.interceptors.request.use(
|
||||
// })
|
||||
// }
|
||||
|
||||
// export default request
|
||||
// export default request
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
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 {cloneDeep} from "lodash-es";
|
||||
import {getDefaultSettingState} from "@/stores/setting.ts";
|
||||
import {Dict, DictResource, DictType, getDefaultArticle, getDefaultDict, getDefaultWord} from "@/types.ts";
|
||||
import {ArchiveReader, libarchiveWasm} from "libarchive-wasm";
|
||||
import {useRouter} from "vue-router";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {nanoid} from "nanoid";
|
||||
@@ -514,3 +512,57 @@ export function convertToWord(raw: any) {
|
||||
custom: true
|
||||
});
|
||||
}
|
||||
|
||||
export function cloneDeep<T>(val: T) {
|
||||
return JSON.parse(JSON.stringify(val))
|
||||
}
|
||||
|
||||
export function shuffle<T>(array: T[]): T[] {
|
||||
const result = array.slice(); // 复制数组,避免修改原数组
|
||||
for (let i = result.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1)); // 生成 0 ~ i 的随机索引
|
||||
[result[i], result[j]] = [result[j], result[i]]; // 交换元素
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function last<T>(array: T[]): T | undefined {
|
||||
return array.length > 0 ? array[array.length - 1] : undefined;
|
||||
}
|
||||
|
||||
export function debounce<T extends (...args: any[]) => void>(func: T, wait: number) {
|
||||
let timer: ReturnType<typeof setTimeout> | null = null;
|
||||
return function (this: ThisParameterType<T>, ...args: Parameters<T>) {
|
||||
if (timer) clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
func.apply(this, args);
|
||||
}, wait);
|
||||
};
|
||||
}
|
||||
|
||||
export function throttle<T extends (...args: any[]) => void>(func: T, wait: number) {
|
||||
let lastTime = 0;
|
||||
return function (this: ThisParameterType<T>, ...args: Parameters<T>) {
|
||||
const now = Date.now();
|
||||
if (now - lastTime >= wait) {
|
||||
func.apply(this, args);
|
||||
lastTime = now;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function reverse<T>(array: T[]): T[] {
|
||||
return array.slice().reverse();
|
||||
}
|
||||
|
||||
export function assign<T extends object, U extends object>(target: T, ...sources: U[]): T & U {
|
||||
return Object.assign(target, ...sources);
|
||||
}
|
||||
|
||||
export function groupBy<T extends Record<string, any>>(array: T[], key: string) {
|
||||
return array.reduce<Record<string, T[]>>((result, item) => {
|
||||
const groupKey = String(item[key]);
|
||||
(result[groupKey] ||= []).push(item);
|
||||
return result;
|
||||
}, {});
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ export default defineConfig({
|
||||
'bg-third': 'bg-[var(--color-third)]',
|
||||
'bg-card-active': 'bg-[var(--color-card-active)]',
|
||||
'color-main': 'color-[var(--color-main-text)]',
|
||||
'gap-space': 'gap-[var(--space)]',
|
||||
},
|
||||
presets: [
|
||||
presetWind3(),
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import {defineConfig} from 'vite'
|
||||
import {defineConfig, UserConfig} from 'vite'
|
||||
import Vue from '@vitejs/plugin-vue'
|
||||
import VueJsx from "@vitejs/plugin-vue-jsx";
|
||||
import {resolve} from 'path'
|
||||
import {visualizer} from "rollup-plugin-visualizer";
|
||||
import SlidePlugin from './src/components/slide/data.js';
|
||||
import {ElementPlusResolver} from "unplugin-vue-components/resolvers";
|
||||
import AutoImport from 'unplugin-auto-import/vite'
|
||||
import Components from 'unplugin-vue-components/vite'
|
||||
import {getLastCommit} from "git-last-commit";
|
||||
import UnoCSS from 'unocss/vite'
|
||||
import VueMacros from 'unplugin-vue-macros/vite'
|
||||
import {Plugin as importToCDN} from 'vite-plugin-cdn-import'
|
||||
import ElementPlus from 'unplugin-element-plus/vite'
|
||||
|
||||
function pathResolve(dir: string) {
|
||||
return resolve(__dirname, ".", dir)
|
||||
@@ -18,7 +16,7 @@ function pathResolve(dir: string) {
|
||||
|
||||
const lifecycle = process.env.npm_lifecycle_event;
|
||||
|
||||
async function getConfig() {
|
||||
async function getConfig(): Promise<Partial<UserConfig>> {
|
||||
const latestCommitHash = await new Promise<string>((resolve) => {
|
||||
return getLastCommit((err, commit) => (err ? 'unknown' : resolve(commit.shortHash)))
|
||||
})
|
||||
@@ -31,12 +29,7 @@ async function getConfig() {
|
||||
},
|
||||
}),
|
||||
UnoCSS(),
|
||||
AutoImport({
|
||||
resolvers: [ElementPlusResolver()],
|
||||
}),
|
||||
Components({
|
||||
resolvers: [ElementPlusResolver()],
|
||||
}),
|
||||
ElementPlus(),
|
||||
lifecycle === 'report' ?
|
||||
visualizer({
|
||||
gzipSize: true,
|
||||
@@ -58,11 +51,11 @@ async function getConfig() {
|
||||
var: 'VueRouter',
|
||||
path: `https://cdn.jsdelivr.net/npm/vue-router@4.5.1/dist/vue-router.global.prod.min.js`
|
||||
},
|
||||
// {
|
||||
// name: 'axios',
|
||||
// var: 'axios',
|
||||
// path: 'https://cdn.jsdelivr.net/npm/axios@1.9.0/dist/axios.min.js'
|
||||
// },
|
||||
{
|
||||
name: 'axios',
|
||||
var: 'axios',
|
||||
path: 'https://cdn.jsdelivr.net/npm/axios@1.9.0/dist/axios.min.js'
|
||||
},
|
||||
]
|
||||
})
|
||||
],
|
||||
@@ -77,6 +70,11 @@ async function getConfig() {
|
||||
},
|
||||
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
|
||||
},
|
||||
// build: {
|
||||
// rollupOptions: {
|
||||
// external: ['axios'],// 使用全局的 axios。因为百度翻译库内部用了0.19版本的axios,会被打包到代码里面
|
||||
// }
|
||||
// },
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
scss: {
|
||||
|
||||
Reference in New Issue
Block a user