Merge branch 'honghuangdc:main' into main

This commit is contained in:
Wang Zheng 2022-11-17 10:11:43 +08:00 committed by GitHub
commit 5efd1dbec4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 348 additions and 401 deletions

1
.gitignore vendored
View File

@ -30,6 +30,5 @@ stats.html
*.sw?
/src/typings/components.d.ts
/src/typings/router-page.d.ts
package-lock.json
yarn.lock

View File

@ -3,25 +3,12 @@
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<link rel="stylesheet" href="/resource/loading.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><%= appName %></title>
</head>
<body>
<div id="app">
<div class="loading-container">
<div id="loadingLogo" class="loading-svg"></div>
<div class="loading-spin__container">
<div class="loading-spin">
<div class="left-0 top-0 loading-spin-item"></div>
<div class="left-0 bottom-0 loading-spin-item loading-delay-500"></div>
<div class="right-0 top-0 loading-spin-item loading-delay-1000"></div>
<div class="right-0 bottom-0 loading-spin-item loading-delay-1500"></div>
</div>
</div>
<div class="loading-title"><%= appTitle %></div>
</div>
<script src="/resource/loading.js"></script>
<div id="appLoading"></div>
</div>
<script type="module" src="/src/main.ts"></script>
</body>

View File

@ -81,11 +81,11 @@
"vue-router": "^4.1.6",
"vuedraggable": "^4.1.0",
"wangeditor": "^4.7.15",
"xgplayer": "^2.32.1"
"xgplayer": "^2.32.2"
},
"devDependencies": {
"@amap/amap-jsapi-types": "^0.0.10",
"@iconify/json": "^2.1.136",
"@iconify/json": "^2.1.139",
"@iconify/vue": "^4.0.0",
"@soybeanjs/router-page": "1.0.3",
"@types/bmapgl": "^0.0.5",
@ -107,7 +107,7 @@
"esno": "^0.16.3",
"husky": "^8.0.2",
"mockjs": "^1.1.0",
"npm-check-updates": "^16.3.25",
"npm-check-updates": "^16.4.1",
"rimraf": "^3.0.2",
"rollup-plugin-visualizer": "^5.8.3",
"sass": "^1.56.1",
@ -117,7 +117,7 @@
"unplugin-vue-components": "0.22.9",
"unplugin-vue-macros": "^0.16.3",
"utility-types": "^3.10.0",
"vite": "^3.2.3",
"vite": "^3.2.4",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-html": "^3.2.0",
"vite-plugin-mock": "^2.9.6",

View File

@ -10,7 +10,7 @@ specifiers:
'@antv/data-set': ^0.11.8
'@antv/g2': ^4.2.8
'@better-scroll/core': ^2.5.0
'@iconify/json': ^2.1.136
'@iconify/json': ^2.1.139
'@iconify/vue': ^4.0.0
'@soybeanjs/router-page': 1.0.3
'@soybeanjs/vue-admin-layout': ^1.1.1
@ -44,7 +44,7 @@ specifiers:
lodash-es: ^4.17.21
mockjs: ^1.1.0
naive-ui: 2.33.5
npm-check-updates: ^16.3.25
npm-check-updates: ^16.4.1
pinia: ^2.0.23
print-js: ^1.6.0
qs: ^6.11.0
@ -60,7 +60,7 @@ specifiers:
unplugin-vue-macros: ^0.16.3
utility-types: ^3.10.0
vditor: ^3.8.18
vite: ^3.2.3
vite: ^3.2.4
vite-plugin-compression: ^0.5.1
vite-plugin-html: ^3.2.0
vite-plugin-mock: ^2.9.6
@ -73,7 +73,7 @@ specifiers:
vue-tsc: ^1.0.9
vuedraggable: ^4.1.0
wangeditor: ^4.7.15
xgplayer: ^2.32.1
xgplayer: ^2.32.2
zx: ^7.1.1
dependencies:
@ -103,11 +103,11 @@ dependencies:
vue-router: 4.1.6_vue@3.2.45
vuedraggable: 4.1.0_vue@3.2.45
wangeditor: 4.7.15
xgplayer: 2.32.1
xgplayer: 2.32.2
devDependencies:
'@amap/amap-jsapi-types': 0.0.10
'@iconify/json': 2.1.136
'@iconify/json': 2.1.139
'@iconify/vue': 4.0.0_vue@3.2.45
'@soybeanjs/router-page': 1.0.3
'@types/bmapgl': 0.0.5
@ -116,9 +116,9 @@ devDependencies:
'@types/qs': 6.9.7
'@types/ua-parser-js': 0.7.36
'@unocss/preset-uno': 0.46.5
'@unocss/vite': 0.46.5_rollup@2.79.1+vite@3.2.3
'@vitejs/plugin-vue': 3.2.0_vite@3.2.3+vue@3.2.45
'@vitejs/plugin-vue-jsx': 2.1.1_vite@3.2.3+vue@3.2.45
'@unocss/vite': 0.46.5_rollup@2.79.1+vite@3.2.4
'@vitejs/plugin-vue': 3.2.0_vite@3.2.4+vue@3.2.45
'@vitejs/plugin-vue-jsx': 2.1.1_vite@3.2.4+vue@3.2.45
commitlint: 17.2.0
conventional-changelog: 3.1.25
cross-env: 7.0.3
@ -129,7 +129,7 @@ devDependencies:
esno: 0.16.3
husky: 8.0.2
mockjs: 1.1.0_3y7clh66jsbznbjsqlxuh6722u
npm-check-updates: 16.3.25
npm-check-updates: 16.4.1
rimraf: 3.0.2
rollup-plugin-visualizer: 5.8.3_rollup@2.79.1
sass: 1.56.1
@ -137,15 +137,15 @@ devDependencies:
typescript: 4.8.4
unplugin-icons: 0.14.13
unplugin-vue-components: 0.22.9_rollup@2.79.1+vue@3.2.45
unplugin-vue-macros: 0.16.3_mtjmd4d7yri6vok5vdb7foxsoq
unplugin-vue-macros: 0.16.3_wngx4xzvqgttz6r2laqlxyas2u
utility-types: 3.10.0
vite: 3.2.3_ajklay5k626t46b6fyghkbup3i
vite-plugin-compression: 0.5.1_vite@3.2.3
vite-plugin-html: 3.2.0_vite@3.2.3
vite-plugin-mock: 2.9.6_qj5sox3st75utfpfnxdchh4ucq
vite-plugin-progress: 0.0.6_vite@3.2.3
vite-plugin-pwa: 0.13.3_jklrv2undatkozcsn24zow6xuu
vite-plugin-svg-icons: 2.0.1_vite@3.2.3
vite: 3.2.4_ajklay5k626t46b6fyghkbup3i
vite-plugin-compression: 0.5.1_vite@3.2.4
vite-plugin-html: 3.2.0_vite@3.2.4
vite-plugin-mock: 2.9.6_55m5mhr4n72hhmialh5t5h2xye
vite-plugin-progress: 0.0.6_vite@3.2.4
vite-plugin-pwa: 0.13.3_ncfuj3sngaz4xbo7yyj2tfhvju
vite-plugin-svg-icons: 2.0.1_vite@3.2.4
vue-tsc: 1.0.9_typescript@4.8.4
zx: 7.1.1
@ -1637,11 +1637,11 @@ packages:
'@types/node': 14.18.33
chalk: 4.1.2
cosmiconfig: 7.1.0
cosmiconfig-typescript-loader: 4.2.0_zhrz2lclwdmp54iaqottwiuipu
cosmiconfig-typescript-loader: 4.2.0_qoh33be55smklb2oyrgdyddh4a
lodash: 4.17.21
resolve-from: 5.0.0
ts-node: 10.9.1_cbe7ovvae6zqfnmtgctpgpys54
typescript: 4.8.4
typescript: 4.9.3
transitivePeerDependencies:
- '@swc/core'
- '@swc/wasm'
@ -1833,8 +1833,8 @@ packages:
engines: {node: '>=6.9.0'}
dev: true
/@iconify/json/2.1.136:
resolution: {integrity: sha512-tO5hV+yXn87+OCQqiVzis6i4YQiRX4044ZjubP6GmbeclE6tsypK+by/tXjbm90GTX0jhsOJ6YLzWl3szivywg==}
/@iconify/json/2.1.139:
resolution: {integrity: sha512-H/DQ/yVgdUk4x4hU696fy0mZOkvLQaR6REQU/okFLgaiIFOS+EWw6GV5JDSKbbkh0YVaxUrAUaqB8XTSFVrFeA==}
dependencies:
'@iconify/types': 2.0.0
pathe: 0.3.9
@ -2569,7 +2569,7 @@ packages:
css-tree: 2.2.1
dev: true
/@unocss/vite/0.46.5_rollup@2.79.1+vite@3.2.3:
/@unocss/vite/0.46.5_rollup@2.79.1+vite@3.2.4:
resolution: {integrity: sha512-/auNcS1L3PjwAA3U/i9scJf2Zx3kkgCdKiXyfetjws4ddAnVE+LrDmIKbbdSUiWFoq9W2QOPpOPpV2xips2gmg==}
peerDependencies:
vite: ^2.9.0 || ^3.0.0-0
@ -2582,12 +2582,12 @@ packages:
'@unocss/scope': 0.46.5
'@unocss/transformer-directives': 0.46.5
magic-string: 0.26.7
vite: 3.2.3_ajklay5k626t46b6fyghkbup3i
vite: 3.2.4_ajklay5k626t46b6fyghkbup3i
transitivePeerDependencies:
- rollup
dev: true
/@vitejs/plugin-vue-jsx/2.1.1_vite@3.2.3+vue@3.2.45:
/@vitejs/plugin-vue-jsx/2.1.1_vite@3.2.4+vue@3.2.45:
resolution: {integrity: sha512-JgDhxstQlwnHBvZ1BSnU5mbmyQ14/t5JhREc6YH5kWyu2QdAAOsLF6xgHoIWarj8tddaiwFrNzLbWJPudpXKYA==}
engines: {node: ^14.18.0 || >=16.0.0}
peerDependencies:
@ -2597,20 +2597,20 @@ packages:
'@babel/core': 7.20.2
'@babel/plugin-transform-typescript': 7.20.2_@babel+core@7.20.2
'@vue/babel-plugin-jsx': 1.1.1_@babel+core@7.20.2
vite: 3.2.3_ajklay5k626t46b6fyghkbup3i
vite: 3.2.4_ajklay5k626t46b6fyghkbup3i
vue: 3.2.45
transitivePeerDependencies:
- supports-color
dev: true
/@vitejs/plugin-vue/3.2.0_vite@3.2.3+vue@3.2.45:
/@vitejs/plugin-vue/3.2.0_vite@3.2.4+vue@3.2.45:
resolution: {integrity: sha512-E0tnaL4fr+qkdCNxJ+Xd0yM31UwMkQje76fsDVBBUCoGOUPexu2VDUYHL8P4CwV+zMvWw6nlRw19OnRKmYAJpw==}
engines: {node: ^14.18.0 || >=16.0.0}
peerDependencies:
vite: ^3.0.0
vue: ^3.2.25
dependencies:
vite: 3.2.3_ajklay5k626t46b6fyghkbup3i
vite: 3.2.4_ajklay5k626t46b6fyghkbup3i
vue: 3.2.45
dev: true
@ -2742,16 +2742,16 @@ packages:
unplugin: 0.10.2
dev: true
/@vue-macros/named-template/0.0.5_pwzry6ifamiyy66hle7uchcfiy:
/@vue-macros/named-template/0.0.5_2aqiuug577r2uhg7pi2e2y3u2a:
resolution: {integrity: sha512-bZRUljNyvOOqeE9dyqXvKPQCLUCcPt1EkThmXqSbxagV29ohyviF8+CCs/8OdmNygLTBIChjP8DexQ3nUIFzUg==}
engines: {node: '>=14.19.0'}
dependencies:
'@rollup/pluginutils': 4.2.1
'@vitejs/plugin-vue': 3.2.0_vite@3.2.3+vue@3.2.45
'@vitejs/plugin-vue': 3.2.0_vite@3.2.4+vue@3.2.45
'@vue-macros/common': 0.13.3
'@vue/compiler-dom': 3.2.45
unplugin: 0.10.2
unplugin-combine: 0.2.8_rollup@2.79.1+vite@3.2.3
unplugin-combine: 0.2.8_rollup@2.79.1+vite@3.2.4
transitivePeerDependencies:
- esbuild
- rollup
@ -2760,14 +2760,14 @@ packages:
- webpack
dev: true
/@vue-macros/setup-component/0.12.7_rollup@2.79.1+vite@3.2.3:
/@vue-macros/setup-component/0.12.7_rollup@2.79.1+vite@3.2.4:
resolution: {integrity: sha512-L0WkJgw0QDwZh4tOjjKIDR0DMIybiOunsaxVqkJjicTb2YaiRUSLq4Wadl8Ttrsd0IEfI51CSlg7Sx0/dKLrlQ==}
engines: {node: '>=14.19.0'}
dependencies:
'@rollup/pluginutils': 4.2.1
'@vue-macros/common': 0.13.3
unplugin: 0.10.2
unplugin-combine: 0.2.8_rollup@2.79.1+vite@3.2.3
unplugin-combine: 0.2.8_rollup@2.79.1+vite@3.2.4
transitivePeerDependencies:
- esbuild
- rollup
@ -4006,7 +4006,7 @@ packages:
vary: 1.1.2
dev: true
/cosmiconfig-typescript-loader/4.2.0_zhrz2lclwdmp54iaqottwiuipu:
/cosmiconfig-typescript-loader/4.2.0_qoh33be55smklb2oyrgdyddh4a:
resolution: {integrity: sha512-NkANeMnaHrlaSSlpKGyvn2R4rqUDeE/9E5YHx+b4nwo0R8dZyAqcih8/gxpCZvqWP9Vf6xuLpMSzSgdVEIM78g==}
engines: {node: '>=12', npm: '>=6'}
peerDependencies:
@ -4018,7 +4018,7 @@ packages:
'@types/node': 14.18.33
cosmiconfig: 7.1.0
ts-node: 10.9.1_cbe7ovvae6zqfnmtgctpgpys54
typescript: 4.8.4
typescript: 4.9.3
dev: true
/cosmiconfig/7.1.0:
@ -7820,8 +7820,8 @@ packages:
npm-normalize-package-bin: 3.0.0
dev: true
/npm-check-updates/16.3.25:
resolution: {integrity: sha512-zrjx6P7LGHYS5e3TNuSqkWQc9m1KLjJIxFERGANN+xEY826NQYG08RwucUD9nRxIlRE9PsGCcMsJJTYJu1DHbA==}
/npm-check-updates/16.4.1:
resolution: {integrity: sha512-g0Uf1kCw0p5boutvu5E4htsjYEDuFT9LxYHYFLldAzWs5012jVikEH1Wdae68xedu4twF4EVbKcs83+G2nGnQg==}
engines: {node: '>=14.14'}
hasBin: true
dependencies:
@ -10396,6 +10396,12 @@ packages:
engines: {node: '>=4.2.0'}
hasBin: true
/typescript/4.9.3:
resolution: {integrity: sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==}
engines: {node: '>=4.2.0'}
hasBin: true
dev: true
/ua-parser-js/1.0.32:
resolution: {integrity: sha512-dXVsz3M4j+5tTiovFVyVqssXBu5HM47//YSOeZ9fQkdDKkfzv2v3PP1jmH6FUyPW+yCSn7aBVK1fGGKNhowdDA==}
dev: false
@ -10595,7 +10601,7 @@ packages:
engines: {node: '>= 0.8'}
dev: true
/unplugin-combine/0.2.8_rollup@2.79.1+vite@3.2.3:
/unplugin-combine/0.2.8_rollup@2.79.1+vite@3.2.4:
resolution: {integrity: sha512-Z38AC/TEjXbVyZ5HjVqo+lADj0/dcfwWC0Z4y0LNhybJzJQwmcMxm+ZsqHY3faauj4YigmlRMdptR5JEW9RuLg==}
engines: {node: '>=14.19.0'}
peerDependencies:
@ -10616,7 +10622,7 @@ packages:
'@antfu/utils': 0.6.3
rollup: 2.79.1
unplugin: 0.10.2
vite: 3.2.3_ajklay5k626t46b6fyghkbup3i
vite: 3.2.4_ajklay5k626t46b6fyghkbup3i
dev: true
/unplugin-icons/0.14.13:
@ -10683,7 +10689,7 @@ packages:
unplugin: 0.10.2
dev: true
/unplugin-vue-macros/0.16.3_mtjmd4d7yri6vok5vdb7foxsoq:
/unplugin-vue-macros/0.16.3_wngx4xzvqgttz6r2laqlxyas2u:
resolution: {integrity: sha512-ADdDS5EjHRZ2esEHSNBw7CS7QLWpqvNJIW0H5EqKgSvtQ+2Hnb8IeRVT0f4mR+wyQvl/ZrlpTs1GvZdsh8eSlw==}
engines: {node: '>=14.19.0'}
peerDependencies:
@ -10696,12 +10702,12 @@ packages:
'@vue-macros/define-render': 0.13.8_vue@3.2.45
'@vue-macros/define-slots': 0.0.5_vue@3.2.45
'@vue-macros/hoist-static': 0.12.7
'@vue-macros/named-template': 0.0.5_pwzry6ifamiyy66hle7uchcfiy
'@vue-macros/setup-component': 0.12.7_rollup@2.79.1+vite@3.2.3
'@vue-macros/named-template': 0.0.5_2aqiuug577r2uhg7pi2e2y3u2a
'@vue-macros/setup-component': 0.12.7_rollup@2.79.1+vite@3.2.4
'@vue-macros/setup-sfc': 0.12.7
'@vue-macros/short-emits': 0.12.8
local-pkg: 0.4.2
unplugin-combine: 0.2.8_rollup@2.79.1+vite@3.2.3
unplugin-combine: 0.2.8_rollup@2.79.1+vite@3.2.4
unplugin-vue-define-options: 0.12.7
vue: 3.2.45
transitivePeerDependencies:
@ -10862,7 +10868,7 @@ packages:
vfile-message: 2.0.4
dev: true
/vite-plugin-compression/0.5.1_vite@3.2.3:
/vite-plugin-compression/0.5.1_vite@3.2.4:
resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==}
peerDependencies:
vite: '>=2.0.0'
@ -10870,12 +10876,12 @@ packages:
chalk: 4.1.2
debug: 4.3.4
fs-extra: 10.1.0
vite: 3.2.3_ajklay5k626t46b6fyghkbup3i
vite: 3.2.4_ajklay5k626t46b6fyghkbup3i
transitivePeerDependencies:
- supports-color
dev: true
/vite-plugin-html/3.2.0_vite@3.2.3:
/vite-plugin-html/3.2.0_vite@3.2.4:
resolution: {integrity: sha512-2VLCeDiHmV/BqqNn5h2V+4280KRgQzCFN47cst3WiNK848klESPQnzuC3okH5XHtgwHH/6s1Ho/YV6yIO0pgoQ==}
peerDependencies:
vite: '>=2.0.0'
@ -10892,10 +10898,10 @@ packages:
html-minifier-terser: 6.1.0
node-html-parser: 5.4.2
pathe: 0.2.0
vite: 3.2.3_ajklay5k626t46b6fyghkbup3i
vite: 3.2.4_ajklay5k626t46b6fyghkbup3i
dev: true
/vite-plugin-mock/2.9.6_qj5sox3st75utfpfnxdchh4ucq:
/vite-plugin-mock/2.9.6_55m5mhr4n72hhmialh5t5h2xye:
resolution: {integrity: sha512-/Rm59oPppe/ncbkSrUuAxIQihlI2YcBmnbR4ST1RA2VzM1C0tEQc1KlbQvnUGhXECAGTaQN2JyasiwXP6EtKgg==}
engines: {node: '>=12.0.0'}
peerDependencies:
@ -10912,13 +10918,13 @@ packages:
fast-glob: 3.2.12
mockjs: 1.1.0_3y7clh66jsbznbjsqlxuh6722u
path-to-regexp: 6.2.1
vite: 3.2.3_ajklay5k626t46b6fyghkbup3i
vite: 3.2.4_ajklay5k626t46b6fyghkbup3i
transitivePeerDependencies:
- rollup
- supports-color
dev: true
/vite-plugin-progress/0.0.6_vite@3.2.3:
/vite-plugin-progress/0.0.6_vite@3.2.4:
resolution: {integrity: sha512-pIK2TVEY4XFGrz10CQDdEufBBCDaV0geRHfXV3abGTBr+OF9O0Zmd3ZDrHJXDv4Rl3qAQP4BTCuPYQ3XqstmqA==}
engines: {node: '>=14', pnpm: '>=7.0.0'}
peerDependencies:
@ -10927,10 +10933,10 @@ packages:
picocolors: 1.0.0
progress: 2.0.3
rd: 2.0.1
vite: 3.2.3_ajklay5k626t46b6fyghkbup3i
vite: 3.2.4_ajklay5k626t46b6fyghkbup3i
dev: true
/vite-plugin-pwa/0.13.3_jklrv2undatkozcsn24zow6xuu:
/vite-plugin-pwa/0.13.3_ncfuj3sngaz4xbo7yyj2tfhvju:
resolution: {integrity: sha512-cjWXpZ7slAY14OKz7M8XdgTIi9wjf6OD6NkhiMAc+ogxnbUrecUwLdRtfGPCPsN2ftut5gaN1jTghb11p6IQAA==}
peerDependencies:
vite: ^3.1.0
@ -10942,14 +10948,14 @@ packages:
fast-glob: 3.2.12
pretty-bytes: 6.0.0
rollup: 2.79.1
vite: 3.2.3_ajklay5k626t46b6fyghkbup3i
vite: 3.2.4_ajklay5k626t46b6fyghkbup3i
workbox-build: 6.5.4
workbox-window: 6.5.4
transitivePeerDependencies:
- supports-color
dev: true
/vite-plugin-svg-icons/2.0.1_vite@3.2.3:
/vite-plugin-svg-icons/2.0.1_vite@3.2.4:
resolution: {integrity: sha512-6ktD+DhV6Rz3VtedYvBKKVA2eXF+sAQVaKkKLDSqGUfnhqXl3bj5PPkVTl3VexfTuZy66PmINi8Q6eFnVfRUmA==}
peerDependencies:
vite: '>=2.0.0'
@ -10962,13 +10968,13 @@ packages:
pathe: 0.2.0
svg-baker: 1.7.0
svgo: 2.8.0
vite: 3.2.3_ajklay5k626t46b6fyghkbup3i
vite: 3.2.4_ajklay5k626t46b6fyghkbup3i
transitivePeerDependencies:
- supports-color
dev: true
/vite/3.2.3_ajklay5k626t46b6fyghkbup3i:
resolution: {integrity: sha512-h8jl1TZ76eGs3o2dIBSsvXDLb1m/Ec1iej8ZMdz+PsaFUsftZeWe2CZOI3qogEsMNaywc17gu0q6cQDzh/weCQ==}
/vite/3.2.4_ajklay5k626t46b6fyghkbup3i:
resolution: {integrity: sha512-Z2X6SRAffOUYTa+sLy3NQ7nlHFU100xwanq1WDwqaiFiCe+25zdxP1TfCS5ojPV2oDDcXudHIoPnI1Z/66B7Yw==}
engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true
peerDependencies:
@ -11427,8 +11433,8 @@ packages:
generate-source-map: 0.0.5
dev: false
/xgplayer/2.32.1:
resolution: {integrity: sha512-jUs6108INqnzEn3DTGre6pHW3KroM2w0VKuJNEvOIkoD2oUB+MW5ZZ0PsIwijX/oQRpmvq422CUgo4uqXVidEQ==}
/xgplayer/2.32.2:
resolution: {integrity: sha512-VWK8Hp5K3Fs5YoHadpyCw2zwuiOimRjkPo2PSJZPYKj59VNnL9oLruZp6cy86LHoAgWELRIQj6Nmw5SkQNByWQ==}
hasBin: true
dependencies:
chalk: 2.4.2

View File

@ -1,91 +0,0 @@
.loading-container {
position: fixed;
left: 0;
top: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
.loading-svg {
width: 128px;
height: 128px;
color: var(--primary-color);
}
.loading-spin__container {
width: 56px;
height: 56px;
margin: 36px 0;
}
.loading-spin {
position: relative;
height: 100%;
animation: loadingSpin 1s linear infinite;
}
.left-0 {
left: 0;
}
.right-0 {
right: 0;
}
.top-0 {
top: 0;
}
.bottom-0 {
bottom: 0;
}
.loading-spin-item {
position: absolute;
height: 16px;
width: 16px;
background-color: var(--primary-color);
border-radius: 8px;
-webkit-animation: loadingPulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
animation: loadingPulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@keyframes loadingSpin {
from {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes loadingPulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: .5;
}
}
.loading-delay-500 {
-webkit-animation-delay: 500ms;
animation-delay: 500ms;
}
.loading-delay-1000 {
-webkit-animation-delay: 1000ms;
animation-delay: 1000ms;
}
.loading-delay-1500 {
-webkit-animation-delay: 1500ms;
animation-delay: 1500ms;
}
.loading-title {
font-size: 28px;
font-weight: 500;
color: #646464;
}

View File

@ -1,44 +0,0 @@
/**
* 初始化加载效果的svg格式logo
* @param {string} id - 元素id
*/
function initSvgLogo(id) {
const svgStr = `<svg width="128px" height="128px" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 158.9 158.9" style="enable-background:new 0 0 158.9 158.9;" xml:space="preserve">
<path style="fill:none" d="M0,158.9C0,106.3,0,53.7,0,1.1C0,0.2,0.2,0,1.1,0c52.2,0,104.5,0,156.7,0c0.9,0,1.1,0.2,1.1,1.1
c0,52.2,0,104.5,0,156.7c0,0.9-0.2,1.1-1.1,1.1C105.2,158.8,52.6,158.8,0,158.9z" />
<path style="fill:currentColor" d="M81.3,55.9c-0.1-11.7-2.9-22.5-9.4-32.4c-1-1.5-2.1-2.9-2.5-4.7c-0.7-3.4,0.9-6.9,4-8.6c3-1.7,6.8-1.2,9.3,1.2
c2.4,2.6,4.4,5.6,5.9,8.8c4.7,8.9,7.6,18.6,8.4,28.6c1,12.5-0.7,25-5.2,36.7c-0.9,2.5-1.9,4.9-3,7.3c-0.3,0.4-0.3,1,0,1.4
c9.6,13.3,21.8,23,37.8,27.2c6.4,1.7,13.1,2.3,19.7,1.6c4.2-0.4,7.9,2.7,8.4,6.9c0.7,4.3-2.3,8.3-6.6,9c0,0,0,0-0.1,0
c-7.7,0.9-15.5,0.5-23-1.3c-13.9-3.1-26.7-10-36.9-19.9c-4.4-4.2-8.4-8.8-11.9-13.7c-0.5-0.8-1.4-1.2-2.3-1.1
c-9.5,0.7-18.8,3.3-27.4,7.6c-11.6,6-20.7,14.6-26.4,26.4c-0.7,1.9-2,3.5-3.7,4.7c-2.9,1.7-6.6,1.5-9.2-0.7c-2.8-2.2-3.8-6-2.4-9.3
c2.2-5.2,5.1-10.1,8.7-14.5c12.2-15.4,28.2-24.6,47.3-28.6c4-0.8,8.1-1.4,12.2-1.6c0.5,0,1-0.3,1.2-0.8c3.3-7.1,5.5-14.6,6.5-22.3
C81.1,61.2,81.3,58.6,81.3,55.9z" />
<path style="fill:currentColor" d="M136.3,108.3c-3.8-0.5-7.6-1.4-11.1-2.9c-7.7-2.8-14.4-7.5-19.7-13.8c-2.9-3.3-2.5-8.4,0.8-11.3
c1.4-1.2,3.1-1.9,4.9-1.9c2.5-0.1,5,1,6.5,2.9c4.9,5.6,11.6,9.4,18.9,10.8c1.5,0.2,3.1,0.6,4.5,1.2c3.2,1.8,4.8,5.6,3.8,9.2
C144,106.1,140.8,108.4,136.3,108.3z" />
<path style="fill:currentColor" d="M55.7,33.3c3,0.2,5.6,2.2,6.6,5c2.2,5.4,3.4,11.2,3.6,17c0.3,5.9-0.6,11.7-2.5,17.3c-2,5.8-8.2,7.8-12.9,4.2
c-2.6-2.2-3.6-5.8-2.4-9c1.4-4,1.9-8.2,1.7-12.4c-0.2-3.8-1-7.5-2.4-11C45.3,38.9,49.2,33.3,55.7,33.3z" />
<path style="fill:currentColor" d="M77.9,126.6c0,3.9-2.8,7.2-6.7,7.9c-7.8,1.5-14.8,5.9-19.7,12.2c-2.7,3.5-7.6,4.2-11.2,1.6
c-3.6-2.6-4.3-7.6-1.7-11.2c0.1-0.1,0.2-0.3,0.3-0.4c4.1-5.2,9.3-9.6,15.1-12.8c4.4-2.5,9.1-4.2,14-5.1
C73.3,117.7,77.9,121.3,77.9,126.6z" />
</svg>`;
const appEl = document.querySelector(id);
const div = document.createElement('div');
div.innerHTML = svgStr;
if (appEl) {
appEl.appendChild(div);
}
}
function addThemeColorCssVars() {
const key = '__THEME_COLOR__';
const defaultColor = '#1890ff';
const themeColor = window.localStorage.getItem(key) || defaultColor;
const cssVars = `--primary-color: ${themeColor}`;
document.documentElement.style.cssText = cssVars;
}
addThemeColorCssVars();
initSvgLogo('#loadingLogo');

View File

@ -0,0 +1,41 @@
<template>
<div class="fixed-center flex-col">
<system-logo class="text-128px text-primary" />
<div class="w-56px h-56px my-36px">
<div class="relative h-full animate-spin">
<div
v-for="(item, index) in lodingClasses"
:key="index"
class="absolute w-16px h-16px bg-primary rounded-8px animate-pulse"
:class="item"
></div>
</div>
</div>
<h2 class="text-28px font-500 text-#646464">{{ title }}</h2>
</div>
</template>
<script setup lang="ts">
import { useAppInfo } from '@/composables';
import { localStg } from '@/utils';
const { title } = useAppInfo();
const lodingClasses = [
'left-0 top-0',
'left-0 bottom-0 animate-delay-500',
'right-0 top-0 animate-delay-1000',
'right-0 bottom-0 animate-delay-1500'
];
function addThemeColorCssVars() {
const defaultColor = '#1890ff';
const themeColor = localStg.get('themeColor') || defaultColor;
const cssVars = `--primary-color: ${themeColor}`;
document.documentElement.style.cssText = cssVars;
}
addThemeColorCssVars();
</script>
<style scoped></style>

View File

@ -5,22 +5,6 @@ export enum EnumContentType {
formData = 'multipart/form-data'
}
/** 缓存的key */
export enum EnumStorageKey {
/** 主题颜色 */
'theme-color' = '__THEME_COLOR__',
/** 用户token */
'token' = '__TOKEN__',
/** 用户刷新token */
'refresh-token' = '__REFRESH_TOKEN__',
/** 用户信息 */
'user-info' = '__USER_INFO__',
/** 主题配置 */
'theme-settings' = '__THEME_SETTINGS__',
/** 多页签路由信息 */
'multi-tab-routes' = '__MULTI_TAB_ROUTES__'
}
/** 数据类型 */
export enum EnumDataType {
number = '[object Number]',

View File

@ -1,5 +1,6 @@
import { createApp } from 'vue';
import App from './App.vue';
import AppLoading from './components/common/AppLoading.vue';
import { setupDirectives } from './directives';
import { setupRouter } from './router';
import { setupAssets } from './plugins';
@ -10,6 +11,11 @@ async function setupApp() {
// import assets: js、css
setupAssets();
// app loading
const appLoading = createApp(AppLoading);
appLoading.mount('#appLoading');
const app = createApp(App);
// store plugin: pinia

View File

@ -1,7 +1,7 @@
import type { NavigationGuardNext, RouteLocationNormalized } from 'vue-router';
import { routeName } from '@/router';
import { useRouteStore } from '@/store';
import { getToken } from '@/utils';
import { localStg } from '@/utils';
/**
*
@ -12,7 +12,7 @@ export async function createDynamicRouteGuard(
next: NavigationGuardNext
) {
const route = useRouteStore();
const isLogin = Boolean(getToken());
const isLogin = Boolean(localStg.get('token'));
// 初始化权限路由
if (!route.isInitAuthRoute) {

View File

@ -1,7 +1,7 @@
import type { NavigationGuardNext, RouteLocationNormalized } from 'vue-router';
import { routeName } from '@/router';
import { useAuthStore } from '@/store';
import { exeStrategyActions, getToken } from '@/utils';
import { exeStrategyActions, localStg } from '@/utils';
import { createDynamicRouteGuard } from './dynamic';
/** 处理路由页面的权限 */
@ -22,7 +22,7 @@ export async function createPermissionGuard(
}
const auth = useAuthStore();
const isLogin = Boolean(getToken());
const isLogin = Boolean(localStg.get('token'));
const permissions = to.meta.permissions || [];
const needLogin = Boolean(to.meta?.requiresAuth) || Boolean(permissions.length);
const hasPermission = !permissions.length || permissions.includes(auth.userInfo.userRole);

View File

@ -1,6 +1,6 @@
import type { AxiosRequestConfig } from 'axios';
import { useAuthStore } from '@/store';
import { getRefreshToken, setRefreshToken, setToken } from '@/utils';
import { localStg } from '@/utils';
import { fetchUpdateToken } from '../api';
/**
@ -9,11 +9,12 @@ import { fetchUpdateToken } from '../api';
*/
export async function handleRefreshToken(axiosConfig: AxiosRequestConfig) {
const { resetAuthStore } = useAuthStore();
const refreshToken = getRefreshToken();
const refreshToken = localStg.get('refreshToken') || '';
const { data } = await fetchUpdateToken(refreshToken);
if (data) {
setToken(data.token);
setRefreshToken(data.refreshToken);
localStg.set('token', data.token);
localStg.set('refreshToken', data.refreshToken);
const config = { ...axiosConfig };
if (config.headers) {
config.headers.Authorization = data.token;

View File

@ -2,7 +2,7 @@ import axios from 'axios';
import type { AxiosError, AxiosInstance, AxiosRequestConfig } from 'axios';
import { REFRESH_TOKEN_CODE } from '@/config';
import {
getToken,
localStg,
handleAxiosError,
handleBackendError,
handleResponseError,
@ -49,7 +49,7 @@ export default class CustomAxiosInstance {
const contentType = handleConfig.headers['Content-Type'] as string;
handleConfig.data = await transformRequestData(handleConfig.data, contentType);
// 设置token
handleConfig.headers.Authorization = getToken();
handleConfig.headers.Authorization = localStg.get('token') || '';
}
return handleConfig;
},

View File

@ -0,0 +1,25 @@
import { localStg } from '@/utils';
/** 获取token */
export function getToken() {
return localStg.get('token') || '';
}
/** 获取用户信息 */
export function getUserInfo() {
const emptyInfo: Auth.UserInfo = {
userId: '',
userName: '',
userRole: 'user'
};
const userInfo: Auth.UserInfo = localStg.get('userInfo') || emptyInfo;
return userInfo;
}
/** 去除用户相关缓存 */
export function clearAuthStorage() {
localStg.remove('token');
localStg.remove('refreshToken');
localStg.remove('userInfo');
}

View File

@ -3,9 +3,10 @@ import { defineStore } from 'pinia';
import { router } from '@/router';
import { fetchLogin, fetchUserInfo } from '@/service';
import { useRouterPush } from '@/composables';
import { clearAuthStorage, getToken, getUserInfo, setRefreshToken, setToken, setUserInfo } from '@/utils';
import { localStg } from '@/utils';
import { useTabStore } from '../tab';
import { useRouteStore } from '../route';
import { getToken, getUserInfo, clearAuthStorage } from './helpers';
interface AuthState {
/** 用户信息 */
@ -81,14 +82,14 @@ export const useAuthStore = defineStore('auth-store', {
// 先把token存储到缓存中(后面接口的请求头需要token)
const { token, refreshToken } = backendToken;
setToken(token);
setRefreshToken(refreshToken);
localStg.set('token', token);
localStg.set('refreshToken', refreshToken);
// 获取用户信息
const { data } = await fetchUserInfo();
if (data) {
// 成功后把用户信息存储到缓存中
setUserInfo(data);
localStg.set('userInfo', data);
// 更新状态
this.userInfo = data;

View File

@ -2,10 +2,10 @@ import { defineStore } from 'pinia';
import { ROOT_ROUTE, constantRoutes, router, routes as staticRoutes } from '@/router';
import { fetchUserRoutes } from '@/service';
import {
localStg,
filterAuthRoutesByUserPermission,
getCacheRoutes,
getConstantRouteNames,
getUserInfo,
transformAuthRouteToVueRoutes,
transformAuthRouteToVueRoute,
transformAuthRouteToMenu,
@ -106,7 +106,12 @@ export const useRouteStore = defineStore('route-store', {
},
/** 初始化动态路由 */
async initDynamicRoute() {
const { userId } = getUserInfo();
const { userId } = localStg.get('userInfo') || {};
if (!userId) {
throw new Error('userId 不能为空!');
}
const { data } = await fetchUserRoutes(userId);
if (data) {
this.routeHomeName = data.home;
@ -123,9 +128,6 @@ export const useRouteStore = defineStore('route-store', {
/** 初始化权限路由 */
async initAuthRoute() {
const { initHomeTab } = useTabStore();
const { userId } = getUserInfo();
if (!userId) return;
const isDynamicRoute = this.authRouteMode === 'dynamic';
if (isDynamicRoute) {

View File

@ -1,6 +1,5 @@
import type { RouteLocationNormalizedLoaded, RouteRecordNormalized } from 'vue-router';
import { EnumStorageKey } from '@/enum';
import { getLocal, setLocal } from '@/utils';
import { localStg } from '@/utils';
/**
* vue路由获取tab路由
@ -58,15 +57,10 @@ function hasFullPath(
return Boolean((route as RouteLocationNormalizedLoaded).fullPath);
}
/** 缓存多页签数据 */
export function setTabRoutes(data: App.GlobalTabRoute[]) {
setLocal(EnumStorageKey['multi-tab-routes'], data);
}
/** 获取缓存的多页签数据 */
export function getTabRoutes() {
const routes: App.GlobalTabRoute[] = [];
const data = getLocal<App.GlobalTabRoute[]>(EnumStorageKey['multi-tab-routes']);
const data = localStg.get('multiTabRoutes');
if (data) {
const defaultTabRoutes = data.map(item => ({
...item,
@ -82,5 +76,5 @@ export function getTabRoutes() {
/** 清空多页签数据 */
export function clearTabRoutes() {
setTabRoutes([]);
localStg.set('multiTabRoutes', []);
}

View File

@ -1,6 +1,7 @@
import type { RouteLocationNormalizedLoaded, Router } from 'vue-router';
import { defineStore } from 'pinia';
import { useRouterPush } from '@/composables';
import { localStg } from '@/utils';
import { useThemeStore } from '../theme';
import {
clearTabRoutes,
@ -8,8 +9,7 @@ import {
getIndexInTabRoutesByRouteName,
getTabRouteByVueRoute,
getTabRoutes,
isInTabRoutes,
setTabRoutes
isInTabRoutes
} from './helpers';
interface TabState {
@ -52,7 +52,7 @@ export const useTabStore = defineStore('tab-store', {
},
/** 缓存页签路由数据 */
cacheTabRoutes() {
setTabRoutes(this.tabs);
localStg.set('multiTabRoutes', this.tabs);
},
/**
*

View File

@ -1,19 +1,18 @@
import type { GlobalThemeOverrides } from 'naive-ui';
import { cloneDeep } from 'lodash-es';
import { themeSetting } from '@/settings';
import { EnumStorageKey } from '@/enum';
import { addColorAlpha, getColorPalette, getLocal, getThemeColor, removeLocal, setLocal } from '@/utils';
import { localStg, addColorAlpha, getColorPalette } from '@/utils';
/** 初始化主题配置 */
export function initThemeSettings() {
const isProd = import.meta.env.PROD;
// 生产环境才缓存主题配置本地开发实时调整配置更改配置的json
const storageSettings = getThemeSettings();
const storageSettings = localStg.get('themeSettings');
if (isProd && storageSettings) {
return storageSettings;
}
const themeColor = getThemeColor() || themeSetting.themeColor;
const themeColor = localStg.get('themeColor') || themeSetting.themeColor;
const info = themeSetting.isCustomizeInfoColor ? themeSetting.otherColor.info : getColorPalette(themeColor, 7);
const otherColor = { ...themeSetting.otherColor, info };
const setting = cloneDeep({ ...themeSetting, themeColor, otherColor });
@ -78,18 +77,3 @@ export function getNaiveThemeOverrides(colors: Record<ColorType, string>): Globa
}
};
}
/** 获取缓存中的主题配置 */
function getThemeSettings() {
return getLocal<Theme.Setting>(EnumStorageKey['theme-settings']);
}
/** 获取缓存中的主题配置 */
export function setThemeSettings(settings: Theme.Setting) {
return setLocal(EnumStorageKey['theme-settings'], settings);
}
/** 清除缓存配置 */
export function clearThemeSettings() {
removeLocal(EnumStorageKey['theme-settings']);
}

View File

@ -1,6 +1,7 @@
import { defineStore } from 'pinia';
import { darkTheme } from 'naive-ui';
import { clearThemeSettings, getNaiveThemeOverrides, initThemeSettings, setThemeSettings } from './helpers';
import { localStg } from '@/utils';
import { getNaiveThemeOverrides, initThemeSettings } from './helpers';
type ThemeState = Theme.Setting;
@ -24,14 +25,14 @@ export const useThemeStore = defineStore('theme-store', {
actions: {
/** 重置theme状态 */
resetThemeStore() {
clearThemeSettings();
localStg.remove('themeSettings');
this.$reset();
},
/** 缓存主题配置 */
cacheThemeSettings() {
const isProd = import.meta.env.PROD;
if (isProd) {
setThemeSettings(this.$state);
localStg.set('themeSettings', this.$state);
}
},
/** 设置暗黑模式 */

View File

@ -3,7 +3,7 @@ import { useOsTheme } from 'naive-ui';
import type { GlobalThemeOverrides } from 'naive-ui';
import { useElementSize } from '@vueuse/core';
import { kebabCase } from 'lodash-es';
import { setThemeColor } from '@/utils';
import { localStg } from '@/utils';
import { useThemeStore } from '../modules';
/** 订阅theme store */
@ -17,7 +17,7 @@ export default function subscribeThemeStore() {
const stopThemeColor = watch(
() => theme.themeColor,
newValue => {
setThemeColor(newValue);
localStg.set('themeColor', newValue);
},
{ immediate: true }
);

67
src/typings/router-page.d.ts vendored Normal file
View File

@ -0,0 +1,67 @@
declare namespace RouterPage {
/** 根路由 */
type RootRouteKey = 'root';
/** 未找到路由(捕获无效路径的路由) */
type NotFoundRouteKey = 'not-found';
/** 页面路由 */
type RouteKey =
| '403'
| '404'
| '500'
| 'about'
| 'auth-demo'
| 'auth-demo_permission'
| 'auth-demo_super'
| 'component'
| 'component_button'
| 'component_card'
| 'component_table'
| 'constant-page'
| 'dashboard'
| 'dashboard_analysis'
| 'dashboard_workbench'
| 'document'
| 'document_naive'
| 'document_project'
| 'document_project-link'
| 'document_vite'
| 'document_vue'
| 'exception'
| 'exception_403'
| 'exception_404'
| 'exception_500'
| 'function'
| 'function_tab'
| 'function_tab-detail'
| 'function_tab-multi-detail'
| 'login'
| 'management'
| 'management_auth'
| 'management_role'
| 'management_route'
| 'management_user'
| 'multi-menu'
| 'multi-menu_first'
| 'multi-menu_first_second'
| 'multi-menu_first_second-new'
| 'multi-menu_first_second-new_third'
| 'not-found'
| 'plugin'
| 'plugin_charts'
| 'plugin_charts_antv'
| 'plugin_charts_echarts'
| 'plugin_copy'
| 'plugin_editor'
| 'plugin_editor_markdown'
| 'plugin_editor_quill'
| 'plugin_icon'
| 'plugin_map'
| 'plugin_print'
| 'plugin_swiper'
| 'plugin_video';
/** 最后一级路由(该级路有对应的vue文件) */
type LastDegreeRouteKey = Extract<RouteKey, '403' | '404' | '500' | 'about' | 'auth-demo_permission' | 'auth-demo_super' | 'component_button' | 'component_card' | 'component_table' | 'constant-page' | 'dashboard_analysis' | 'dashboard_workbench' | 'document_naive' | 'document_project' | 'document_project-link' | 'document_vite' | 'document_vue' | 'exception_403' | 'exception_404' | 'exception_500' | 'function_tab' | 'function_tab-detail' | 'function_tab-multi-detail' | 'login' | 'management_auth' | 'management_role' | 'management_route' | 'management_user' | 'multi-menu_first_second' | 'multi-menu_first_second-new_third' | 'not-found' | 'plugin_charts_antv' | 'plugin_charts_echarts' | 'plugin_copy' | 'plugin_editor_markdown' | 'plugin_editor_quill' | 'plugin_icon' | 'plugin_map' | 'plugin_print' | 'plugin_swiper' | 'plugin_video'>
}

22
src/typings/storage.d.ts vendored Normal file
View File

@ -0,0 +1,22 @@
declare namespace StorageInterface {
/** localStorage的存储数据的类型 */
interface Session {
demoKey: string;
}
/** localStorage的存储数据的类型 */
interface Local {
/** 主题颜色 */
themeColor: string;
/** 用户token */
token: string;
/** 用户刷新token */
refreshToken: string;
/** 用户信息 */
userInfo: Auth.UserInfo;
/** 主题配置 */
themeSettings: Theme.Setting;
/** 多页签路由信息 */
multiTabRoutes: App.GlobalTabRoute[];
}
}

View File

@ -1 +0,0 @@
export * from './user';

View File

@ -1,60 +0,0 @@
import { EnumStorageKey } from '@/enum';
import { getLocal, removeLocal, setLocal } from '../storage';
/** 设置token */
export function setToken(token: string) {
setLocal(EnumStorageKey.token, token);
}
/** 获取token */
export function getToken() {
return getLocal<string>(EnumStorageKey.token) || '';
}
/** 去除token */
export function removeToken() {
removeLocal(EnumStorageKey.token);
}
/** 获取refresh token */
export function getRefreshToken() {
return getLocal<string>(EnumStorageKey['refresh-token']) || '';
}
/** 设置refresh token */
export function setRefreshToken(token: string) {
setLocal(EnumStorageKey['refresh-token'], token);
}
/** 去除refresh token */
export function removeRefreshToken() {
removeLocal(EnumStorageKey['refresh-token']);
}
/** 获取用户信息 */
export function getUserInfo() {
const emptyInfo: Auth.UserInfo = {
userId: '',
userName: '',
userRole: 'user'
};
const userInfo: Auth.UserInfo = getLocal<Auth.UserInfo>(EnumStorageKey['user-info']) || emptyInfo;
return userInfo;
}
/** 设置用户信息 */
export function setUserInfo(userInfo: Auth.UserInfo) {
setLocal(EnumStorageKey['user-info'], userInfo);
}
/** 去除用户信息 */
export function removeUserInfo() {
removeLocal(EnumStorageKey['user-info']);
}
/** 去除用户相关缓存 */
export function clearAuthStorage() {
removeToken();
removeRefreshToken();
removeUserInfo();
}

View File

@ -1,6 +1,4 @@
export * from './typeof';
export * from './color';
export * from './number';
export * from './object';
export * from './pattern';
export * from './theme';

View File

@ -1,4 +0,0 @@
/** 设置对象数据 */
export function objectAssign<T extends Record<string, any>>(target: T, source: Partial<T>) {
Object.assign(target, source);
}

View File

@ -1,16 +0,0 @@
import { EnumStorageKey } from '@/enum';
/**
*
* @param color
*/
export function setThemeColor(color: string) {
window.localStorage.setItem(EnumStorageKey['theme-color'], color);
}
/**
*
*/
export function getThemeColor() {
return window.localStorage.getItem(EnumStorageKey['theme-color']);
}

View File

@ -1,6 +1,5 @@
export * from './common';
export * from './storage';
export * from './service';
export * from './auth';
export * from './router';
export * from './form';

View File

@ -1,45 +1,57 @@
import { decrypto, encrypto } from '../crypto';
interface StorageData {
value: unknown;
interface StorageData<T> {
value: T;
expire: number | null;
}
/** 默认缓存期限为7天 */
const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7;
function createLocalStorage<T extends StorageInterface.Local = StorageInterface.Local>() {
/** 默认缓存期限为7天 */
const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7;
export function setLocal(key: string, value: unknown, expire: number | null = DEFAULT_CACHE_TIME) {
const storageData: StorageData = { value, expire: expire !== null ? new Date().getTime() + expire * 1000 : null };
const json = encrypto(storageData);
window.localStorage.setItem(key, json);
}
function set<K extends keyof T>(key: K, value: T[K], expire: number | null = DEFAULT_CACHE_TIME) {
const storageData: StorageData<T[K]> = {
value,
expire: expire !== null ? new Date().getTime() + expire * 1000 : null
};
const json = encrypto(storageData);
window.localStorage.setItem(key as string, json);
}
export function getLocal<T>(key: string) {
const json = window.localStorage.getItem(key);
if (json) {
let storageData: StorageData | null = null;
try {
storageData = decrypto(json);
} catch {
// 防止解析失败
}
if (storageData) {
const { value, expire } = storageData;
// 在有效期内直接返回
if (expire === null || expire >= Date.now()) {
return value as T;
function get<K extends keyof T>(key: K) {
const json = window.localStorage.getItem(key as string);
if (json) {
let storageData: StorageData<T[K]> | null = null;
try {
storageData = decrypto(json);
} catch {
// 防止解析失败
}
if (storageData) {
const { value, expire } = storageData;
// 在有效期内直接返回
if (expire === null || expire >= Date.now()) {
return value as T[K];
}
}
remove(key);
return null;
}
removeLocal(key);
return null;
}
return null;
function remove(key: keyof T) {
window.localStorage.removeItem(key as string);
}
function clear() {
window.localStorage.clear();
}
return {
set,
get,
remove,
clear
};
}
export function removeLocal(key: string) {
window.localStorage.removeItem(key);
}
export function clearLocal() {
window.localStorage.clear();
}
export const localStg = createLocalStorage();

View File

@ -25,3 +25,37 @@ export function removeSession(key: string) {
export function clearSession() {
window.sessionStorage.clear();
}
function createSessionStorage<T extends StorageInterface.Session = StorageInterface.Session>() {
function set<K extends keyof T>(key: K, value: T[K]) {
const json = encrypto(value);
sessionStorage.setItem(key as string, json);
}
function get<K extends keyof T>(key: K) {
const json = sessionStorage.getItem(key as string);
let data: T[K] | null = null;
if (json) {
try {
data = decrypto(json);
} catch {
// 防止解析失败
}
}
return data;
}
function remove(key: keyof T) {
window.sessionStorage.removeItem(key as string);
}
function clear() {
window.sessionStorage.clear();
}
return {
set,
get,
remove,
clear
};
}
export const sessionStg = createSessionStorage();