chore: 解决 prettier 与 eslint 冲突 & 格式化所有文件

This commit is contained in:
pany 2022-04-22 01:16:02 +08:00
parent 1c46b05d07
commit 1f62be479a
70 changed files with 551 additions and 1076 deletions

View File

@ -6,78 +6,76 @@ module.exports = {
es6: true
},
globals: {
defineProps: 'readonly',
defineEmits: 'readonly',
defineExpose: 'readonly'
},
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2020
// script setup
defineProps: "readonly",
defineEmits: "readonly",
defineExpose: "readonly",
withDefaults: "readonly"
},
extends: [
'plugin:vue/vue3-recommended',
'plugin:vue/vue3-strongly-recommended',
'plugin:@typescript-eslint/recommended',
'@vue/standard',
'@vue/typescript/recommended'
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/typescript/recommended",
"@vue/prettier",
"@vue/eslint-config-typescript"
],
parser: "vue-eslint-parser",
parserOptions: {
parser: "@typescript-eslint/parser",
ecmaVersion: 2020,
sourceType: "module",
jsxPragma: "React",
ecmaFeatures: {
jsx: true,
tsx: true
}
},
rules: {
'vue/multi-word-component-names': 'off',
'vue/comment-directive': 'off',
'no-console': 'off',
'no-debugger': import.meta.env.MODE === 'production' ? 'warn' : 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/member-delimiter-style': [
'error',
// ts
"@typescript-eslint/no-explicit-any": "off",
"no-debugger": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
multiline: {
delimiter: 'none'
argsIgnorePattern: "^_",
varsIgnorePattern: "^_"
}
],
"no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_"
}
],
// vue
"vue/no-v-html": "off",
"vue/require-default-prop": "off",
"vue/require-explicit-emits": "off",
"vue/multi-word-component-names": "off",
"vue/html-self-closing": [
"error",
{
html: {
void: "always",
normal: "always",
component: "always"
},
singleline: {
delimiter: 'comma'
}
svg: "always",
math: "always"
}
],
// 'vue/html-self-closing': [
// 'error',
// {
// html: {
// void: 'always',
// normal: 'always',
// component: 'always'
// },
// svg: 'always',
// math: 'always'
// }
// ],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-var-requires': 'off',
'prefer-regex-literals': 'off',
'space-before-function-paren': ['error', 'never'],
'vue/array-bracket-spacing': 'error',
'vue/arrow-spacing': 'error',
'vue/block-spacing': 'error',
'vue/brace-style': 'error',
'vue/camelcase': 'error',
'vue/comma-dangle': 'error',
'vue/component-name-in-template-casing': 'error',
'vue/eqeqeq': 'error',
'vue/key-spacing': 'error',
'vue/match-component-file-name': 'error',
'vue/object-curly-spacing': 'error',
'vue/max-attributes-per-line': 'off',
'vue/html-closing-bracket-newline': 'off',
'no-useless-escape': 'off',
'@typescript-eslint/no-this-alias': [
'error',
// prettier
"prettier/prettier": [
"error",
{
allowDestructuring: true, // Allow `const { props, state } = this`; false by default
allowedNames: ['self'] // Allow `const self = this`; `[]` by default
endOfLine: "auto"
}
],
'vue/attribute-hyphenation': 'off',
'vue/custom-event-name-casing': 'off',
'dot-notation': 'off'
]
}
}

View File

@ -4,6 +4,18 @@
模板代码是从 [v3-admin v3.1.3](https://github.com/un-pany/v3-admin) 迁移而来,只是脚手架从 vue-cli 5.x 切换到了 vite并作了一些繁琐我适配.
现在还是预发布 3.1.3-rc1 版本,各位拿来测试即可,谨慎用上生产环境.
现在还是预发布 **3.1.3-rc2** 版本正在努力重构中等待正式版v3.1.3)发布.
文档暂无,可以先用到 v3-admin 的文档,基本上是适用的.
## 开发
- 编辑器 vscode
- 安装 .vscode 中推荐的插件
- node 版本 16+
- pnpm 版本 6.x
- 安装依赖: pnpm i
- 运行项目: pnpm dev
- 打包测试环境: pnpm build:stage
- 打包正式环境: pnpm build:prod
- 代码检测: pnpm lint

View File

@ -1,14 +1,16 @@
{
"name": "v3-admin-vite",
"private": true,
"version": "3.1.3-rc1",
"version": "3.1.3-rc2",
"scripts": {
"dev": "vite",
"build:stage": "vue-tsc --noEmit && vite build --mode staging",
"build:prod": "vue-tsc --noEmit && vite build",
"preview:stage": "pnpm build:stage && vite preview",
"preview:prod": "pnpm build:prod && vite preview",
"lint": "eslint \"{src,mock}/**/*.{vue,ts,tsx}\" --fix"
"lint:eslint": "eslint \"src/**/*.{vue,ts,tsx}\" --fix",
"lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
"lint": "pnpm lint:eslint && pnpm lint:prettier"
},
"dependencies": {
"@element-plus/icons-vue": "^1.1.4",
@ -35,20 +37,20 @@
"@typescript-eslint/eslint-plugin": "^5.20.0",
"@typescript-eslint/parser": "^5.20.0",
"@vitejs/plugin-vue": "^2.3.1",
"@vue/eslint-config-standard": "^6.1.0",
"@vue/eslint-config-prettier": "^7.0.0",
"@vue/eslint-config-typescript": "^10.0.0",
"eslint": "^8.13.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.6.0",
"lint-staged": "^12.4.0",
"prettier": "^2.6.2",
"sass": "^1.50.1",
"typescript": "^4.6.3",
"unplugin-auto-import": "^0.7.1",
"unplugin-vue-components": "^0.19.3",
"vite": "^2.9.5",
"vite-plugin-svg-icons": "^2.0.1",
"vue-eslint-parser": "^8.3.0",
"vue-tsc": "^0.34.7"
},
"gitHooks": {

563
pnpm-lock.yaml generated
View File

@ -10,15 +10,13 @@ specifiers:
'@typescript-eslint/eslint-plugin': ^5.20.0
'@typescript-eslint/parser': ^5.20.0
'@vitejs/plugin-vue': ^2.3.1
'@vue/eslint-config-standard': ^6.1.0
'@vue/eslint-config-prettier': ^7.0.0
'@vue/eslint-config-typescript': ^10.0.0
axios: ^0.26.1
dayjs: ^1.11.1
element-plus: ^2.1.10
eslint: ^8.13.0
eslint-plugin-import: ^2.26.0
eslint-plugin-node: ^11.1.0
eslint-plugin-promise: ^6.0.0
eslint-plugin-prettier: ^4.0.0
eslint-plugin-vue: ^8.6.0
js-cookie: ^3.0.1
lint-staged: ^12.4.0
@ -28,6 +26,7 @@ specifiers:
path-browserify: ^1.0.1
path-to-regexp: ^6.2.0
pinia: ^2.0.13
prettier: ^2.6.2
sass: ^1.50.1
screenfull: ^6.0.1
typescript: ^4.6.3
@ -36,6 +35,7 @@ specifiers:
vite: ^2.9.5
vite-plugin-svg-icons: ^2.0.1
vue: ^3.2.33
vue-eslint-parser: ^8.3.0
vue-router: ^4.0.14
vue-tsc: ^0.34.7
@ -64,20 +64,20 @@ devDependencies:
'@typescript-eslint/eslint-plugin': 5.20.0_b9ac9b5656ce5dffade639fcf5e491bf
'@typescript-eslint/parser': 5.20.0_eslint@8.13.0+typescript@4.6.3
'@vitejs/plugin-vue': 2.3.1_vite@2.9.5+vue@3.2.33
'@vue/eslint-config-standard': 6.1.0_4095fd5e90f154d95a11e7814517bad8
'@vue/eslint-config-prettier': 7.0.0_eslint@8.13.0+prettier@2.6.2
'@vue/eslint-config-typescript': 10.0.0_a62cbc2f4797496d74696b1f6538012a
eslint: 8.13.0
eslint-plugin-import: 2.26.0_eslint@8.13.0
eslint-plugin-node: 11.1.0_eslint@8.13.0
eslint-plugin-promise: 6.0.0_eslint@8.13.0
eslint-plugin-prettier: 4.0.0_eslint@8.13.0+prettier@2.6.2
eslint-plugin-vue: 8.6.0_eslint@8.13.0
lint-staged: 12.4.0
prettier: 2.6.2
sass: 1.50.1
typescript: 4.6.3
unplugin-auto-import: 0.7.1_vite@2.9.5
unplugin-vue-components: 0.19.3_vite@2.9.5+vue@3.2.33
vite: 2.9.5_sass@1.50.1
vite-plugin-svg-icons: 2.0.1_vite@2.9.5
vue-eslint-parser: 8.3.0_eslint@8.13.0
vue-tsc: 0.34.7_typescript@4.6.3
packages:
@ -192,10 +192,6 @@ packages:
resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
dev: true
/@types/json5/0.0.29:
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
dev: true
/@types/lodash-es/4.17.6:
resolution: {integrity: sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==}
dependencies:
@ -427,29 +423,16 @@ packages:
resolution: {integrity: sha512-IiA0SvDrJEgXvVxjNkHPFfDx6SXw0b/TUkqMcDZWNg9fnCAHbTpoo59YfJ9QLFkwa3raau5vSlRVzMSLDnfdtQ==}
dev: false
/@vue/eslint-config-standard/6.1.0_4095fd5e90f154d95a11e7814517bad8:
resolution: {integrity: sha512-9+hrEyflDzsGdlBDl9jPV5DIYUx1TOU5OSQqRDKCrNumrxRj5HRWKuk+ocXWnha6uoNRtLC24mY7d/MwqvBCNw==}
/@vue/eslint-config-prettier/7.0.0_eslint@8.13.0+prettier@2.6.2:
resolution: {integrity: sha512-/CTc6ML3Wta1tCe1gUeO0EYnVXfo3nJXsIhZ8WJr3sov+cGASr6yuiibJTL6lmIBm7GobopToOuB3B6AWyV0Iw==}
peerDependencies:
'@vue/cli-service': ^3.0.0 || ^4.0.0 || ^5.0.0-0
eslint: ^7.12.1
eslint-plugin-import: ^2.22.1
eslint-plugin-node: ^11.1.0
eslint-plugin-promise: ^4.2.1 || ^5.0.0
eslint-plugin-vue: ^7.0.0
peerDependenciesMeta:
'@vue/cli-service':
optional: true
eslint: '>= 7.28.0'
prettier: '>= 2.0.0'
dependencies:
eslint: 8.13.0
eslint-config-standard: 16.0.3_4e3767bb061a43bc3978ec6596bc3350
eslint-import-resolver-node: 0.3.6
eslint-import-resolver-webpack: 0.13.2_eslint-plugin-import@2.26.0
eslint-plugin-import: 2.26.0_eslint@8.13.0
eslint-plugin-node: 11.1.0_eslint@8.13.0
eslint-plugin-promise: 6.0.0_eslint@8.13.0
eslint-plugin-vue: 8.6.0_eslint@8.13.0
transitivePeerDependencies:
- webpack
eslint-config-prettier: 8.5.0_eslint@8.13.0
eslint-plugin-prettier: 4.0.0_1815ac95b7fb26c13c7d48a8eef62d0f
prettier: 2.6.2
dev: true
/@vue/eslint-config-typescript/10.0.0_a62cbc2f4797496d74696b1f6538012a:
@ -644,21 +627,6 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/array-find/1.0.0:
resolution: {integrity: sha512-kO/vVCacW9mnpn3WPWbTVlEnOabK2L7LWi2HViURtCM46y1zb6I8UMjx4LgbiqadTgHnLInUronwn3ampNTJtQ==}
dev: true
/array-includes/3.1.4:
resolution: {integrity: sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
define-properties: 1.1.4
es-abstract: 1.19.5
get-intrinsic: 1.1.1
is-string: 1.0.7
dev: true
/array-union/2.1.0:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'}
@ -669,16 +637,6 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/array.prototype.flat/1.3.0:
resolution: {integrity: sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
define-properties: 1.1.4
es-abstract: 1.19.5
es-shim-unscopables: 1.0.0
dev: true
/assign-symbols/1.0.0:
resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==}
engines: {node: '>=0.10.0'}
@ -792,13 +750,6 @@ packages:
unset-value: 1.0.0
dev: true
/call-bind/1.0.2:
resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
dependencies:
function-bind: 1.1.1
get-intrinsic: 1.1.1
dev: true
/callsites/3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
@ -988,12 +939,6 @@ packages:
ms: 2.0.0
dev: true
/debug/3.2.7:
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
dependencies:
ms: 2.1.2
dev: true
/debug/4.3.4:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
engines: {node: '>=6.0'}
@ -1028,14 +973,6 @@ packages:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: true
/define-properties/1.1.4:
resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==}
engines: {node: '>= 0.4'}
dependencies:
has-property-descriptors: 1.0.0
object-keys: 1.1.1
dev: true
/define-property/0.2.5:
resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==}
engines: {node: '>=0.10.0'}
@ -1065,13 +1002,6 @@ packages:
path-type: 4.0.0
dev: true
/doctrine/2.1.0:
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
engines: {node: '>=0.10.0'}
dependencies:
esutils: 2.0.3
dev: true
/doctrine/3.0.0:
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
engines: {node: '>=6.0.0'}
@ -1172,15 +1102,6 @@ packages:
engines: {node: '>= 4'}
dev: true
/enhanced-resolve/0.9.1:
resolution: {integrity: sha512-kxpoMgrdtkXZ5h0SeraBS1iRntpTpQ3R8ussdb38+UAFnMGX5DDyJXePm+OCHOcoXvHDw7mc2erbJBpDnl7TPw==}
engines: {node: '>=0.6'}
dependencies:
graceful-fs: 4.2.10
memory-fs: 0.2.0
tapable: 0.1.10
dev: true
/entities/1.1.2:
resolution: {integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==}
dev: true
@ -1189,47 +1110,6 @@ packages:
resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==}
dev: true
/es-abstract/1.19.5:
resolution: {integrity: sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
es-to-primitive: 1.2.1
function-bind: 1.1.1
get-intrinsic: 1.1.1
get-symbol-description: 1.0.0
has: 1.0.3
has-symbols: 1.0.3
internal-slot: 1.0.3
is-callable: 1.2.4
is-negative-zero: 2.0.2
is-regex: 1.1.4
is-shared-array-buffer: 1.0.2
is-string: 1.0.7
is-weakref: 1.0.2
object-inspect: 1.12.0
object-keys: 1.1.1
object.assign: 4.1.2
string.prototype.trimend: 1.0.4
string.prototype.trimstart: 1.0.4
unbox-primitive: 1.0.1
dev: true
/es-shim-unscopables/1.0.0:
resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==}
dependencies:
has: 1.0.3
dev: true
/es-to-primitive/1.2.1:
resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
engines: {node: '>= 0.4'}
dependencies:
is-callable: 1.2.4
is-date-object: 1.0.5
is-symbol: 1.0.4
dev: true
/esbuild-android-64/0.14.36:
resolution: {integrity: sha512-jwpBhF1jmo0tVCYC/ORzVN+hyVcNZUWuozGcLHfod0RJCedTDTvR4nwlTXdx1gtncDqjk33itjO+27OZHbiavw==}
engines: {node: '>=12'}
@ -1452,111 +1332,46 @@ packages:
engines: {node: '>=10'}
dev: true
/eslint-config-standard/16.0.3_4e3767bb061a43bc3978ec6596bc3350:
resolution: {integrity: sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==}
/eslint-config-prettier/8.5.0_eslint@8.13.0:
resolution: {integrity: sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==}
hasBin: true
peerDependencies:
eslint: ^7.12.1
eslint-plugin-import: ^2.22.1
eslint-plugin-node: ^11.1.0
eslint-plugin-promise: ^4.2.1 || ^5.0.0
eslint: '>=7.0.0'
dependencies:
eslint: 8.13.0
eslint-plugin-import: 2.26.0_eslint@8.13.0
eslint-plugin-node: 11.1.0_eslint@8.13.0
eslint-plugin-promise: 6.0.0_eslint@8.13.0
dev: true
/eslint-import-resolver-node/0.3.6:
resolution: {integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==}
dependencies:
debug: 3.2.7
resolve: 1.22.0
dev: true
/eslint-import-resolver-webpack/0.13.2_eslint-plugin-import@2.26.0:
resolution: {integrity: sha512-XodIPyg1OgE2h5BDErz3WJoK7lawxKTJNhgPNafRST6csC/MZC+L5P6kKqsZGRInpbgc02s/WZMrb4uGJzcuRg==}
engines: {node: '>= 6'}
/eslint-plugin-prettier/4.0.0_1815ac95b7fb26c13c7d48a8eef62d0f:
resolution: {integrity: sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==}
engines: {node: '>=6.0.0'}
peerDependencies:
eslint-plugin-import: '>=1.4.0'
webpack: '>=1.11.0'
dependencies:
array-find: 1.0.0
debug: 3.2.7
enhanced-resolve: 0.9.1
eslint-plugin-import: 2.26.0_eslint@8.13.0
find-root: 1.1.0
has: 1.0.3
interpret: 1.4.0
is-core-module: 2.9.0
is-regex: 1.1.4
lodash: 4.17.21
resolve: 1.22.0
semver: 5.7.1
dev: true
/eslint-module-utils/2.7.3:
resolution: {integrity: sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==}
engines: {node: '>=4'}
dependencies:
debug: 3.2.7
find-up: 2.1.0
dev: true
/eslint-plugin-es/3.0.1_eslint@8.13.0:
resolution: {integrity: sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==}
engines: {node: '>=8.10.0'}
peerDependencies:
eslint: '>=4.19.1'
eslint: '>=7.28.0'
eslint-config-prettier: '*'
prettier: '>=2.0.0'
peerDependenciesMeta:
eslint-config-prettier:
optional: true
dependencies:
eslint: 8.13.0
eslint-utils: 2.1.0
regexpp: 3.2.0
eslint-config-prettier: 8.5.0_eslint@8.13.0
prettier: 2.6.2
prettier-linter-helpers: 1.0.0
dev: true
/eslint-plugin-import/2.26.0_eslint@8.13.0:
resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==}
engines: {node: '>=4'}
/eslint-plugin-prettier/4.0.0_eslint@8.13.0+prettier@2.6.2:
resolution: {integrity: sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==}
engines: {node: '>=6.0.0'}
peerDependencies:
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
dependencies:
array-includes: 3.1.4
array.prototype.flat: 1.3.0
debug: 2.6.9
doctrine: 2.1.0
eslint: 8.13.0
eslint-import-resolver-node: 0.3.6
eslint-module-utils: 2.7.3
has: 1.0.3
is-core-module: 2.9.0
is-glob: 4.0.3
minimatch: 3.1.2
object.values: 1.1.5
resolve: 1.22.0
tsconfig-paths: 3.14.1
dev: true
/eslint-plugin-node/11.1.0_eslint@8.13.0:
resolution: {integrity: sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==}
engines: {node: '>=8.10.0'}
peerDependencies:
eslint: '>=5.16.0'
dependencies:
eslint: 8.13.0
eslint-plugin-es: 3.0.1_eslint@8.13.0
eslint-utils: 2.1.0
ignore: 5.2.0
minimatch: 3.1.2
resolve: 1.22.0
semver: 6.3.0
dev: true
/eslint-plugin-promise/6.0.0_eslint@8.13.0:
resolution: {integrity: sha512-7GPezalm5Bfi/E22PnQxDWH2iW9GTvAlUNTztemeHb6c1BniSyoeTrM87JkC0wYdi6aQrZX9p2qEiAno8aTcbw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
eslint: '>=7.28.0'
eslint-config-prettier: '*'
prettier: '>=2.0.0'
peerDependenciesMeta:
eslint-config-prettier:
optional: true
dependencies:
eslint: 8.13.0
prettier: 2.6.2
prettier-linter-helpers: 1.0.0
dev: true
/eslint-plugin-vue/8.6.0_eslint@8.13.0:
@ -1590,13 +1405,6 @@ packages:
estraverse: 5.3.0
dev: true
/eslint-utils/2.1.0:
resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==}
engines: {node: '>=6'}
dependencies:
eslint-visitor-keys: 1.3.0
dev: true
/eslint-utils/3.0.0_eslint@8.13.0:
resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==}
engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0}
@ -1607,11 +1415,6 @@ packages:
eslint-visitor-keys: 2.1.0
dev: true
/eslint-visitor-keys/1.3.0:
resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==}
engines: {node: '>=4'}
dev: true
/eslint-visitor-keys/2.1.0:
resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==}
engines: {node: '>=10'}
@ -1773,6 +1576,10 @@ packages:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: true
/fast-diff/1.2.0:
resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==}
dev: true
/fast-glob/3.2.11:
resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==}
engines: {node: '>=8.6.0'}
@ -1822,17 +1629,6 @@ packages:
to-regex-range: 5.0.1
dev: true
/find-root/1.1.0:
resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
dev: true
/find-up/2.1.0:
resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==}
engines: {node: '>=4'}
dependencies:
locate-path: 2.0.0
dev: true
/flat-cache/3.0.4:
resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==}
engines: {node: ^10.12.0 || >=12.0.0}
@ -1896,27 +1692,11 @@ packages:
resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==}
dev: true
/get-intrinsic/1.1.1:
resolution: {integrity: sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==}
dependencies:
function-bind: 1.1.1
has: 1.0.3
has-symbols: 1.0.3
dev: true
/get-stream/6.0.1:
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
engines: {node: '>=10'}
dev: true
/get-symbol-description/1.0.0:
resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
get-intrinsic: 1.1.1
dev: true
/get-value/2.0.6:
resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==}
engines: {node: '>=0.10.0'}
@ -1977,10 +1757,6 @@ packages:
ansi-regex: 2.1.1
dev: true
/has-bigints/1.0.2:
resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
dev: true
/has-flag/1.0.0:
resolution: {integrity: sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==}
engines: {node: '>=0.10.0'}
@ -1991,24 +1767,6 @@ packages:
engines: {node: '>=8'}
dev: true
/has-property-descriptors/1.0.0:
resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==}
dependencies:
get-intrinsic: 1.1.1
dev: true
/has-symbols/1.0.3:
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
engines: {node: '>= 0.4'}
dev: true
/has-tostringtag/1.0.0:
resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==}
engines: {node: '>= 0.4'}
dependencies:
has-symbols: 1.0.3
dev: true
/has-value/0.3.1:
resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==}
engines: {node: '>=0.10.0'}
@ -2112,20 +1870,6 @@ packages:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
dev: true
/internal-slot/1.0.3:
resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==}
engines: {node: '>= 0.4'}
dependencies:
get-intrinsic: 1.1.1
has: 1.0.3
side-channel: 1.0.4
dev: true
/interpret/1.4.0:
resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==}
engines: {node: '>= 0.10'}
dev: true
/is-accessor-descriptor/0.1.6:
resolution: {integrity: sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==}
engines: {node: '>=0.10.0'}
@ -2140,12 +1884,6 @@ packages:
kind-of: 6.0.3
dev: true
/is-bigint/1.0.4:
resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
dependencies:
has-bigints: 1.0.2
dev: true
/is-binary-path/2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
@ -2153,23 +1891,10 @@ packages:
binary-extensions: 2.2.0
dev: true
/is-boolean-object/1.1.2:
resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
has-tostringtag: 1.0.0
dev: true
/is-buffer/1.1.6:
resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
dev: true
/is-callable/1.2.4:
resolution: {integrity: sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==}
engines: {node: '>= 0.4'}
dev: true
/is-core-module/2.9.0:
resolution: {integrity: sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==}
dependencies:
@ -2190,13 +1915,6 @@ packages:
kind-of: 6.0.3
dev: true
/is-date-object/1.0.5:
resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
engines: {node: '>= 0.4'}
dependencies:
has-tostringtag: 1.0.0
dev: true
/is-descriptor/0.1.6:
resolution: {integrity: sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==}
engines: {node: '>=0.10.0'}
@ -2249,18 +1967,6 @@ packages:
is-extglob: 2.1.1
dev: true
/is-negative-zero/2.0.2:
resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==}
engines: {node: '>= 0.4'}
dev: true
/is-number-object/1.0.7:
resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
engines: {node: '>= 0.4'}
dependencies:
has-tostringtag: 1.0.0
dev: true
/is-number/3.0.0:
resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==}
engines: {node: '>=0.10.0'}
@ -2285,45 +1991,11 @@ packages:
isobject: 3.0.1
dev: true
/is-regex/1.1.4:
resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
has-tostringtag: 1.0.0
dev: true
/is-shared-array-buffer/1.0.2:
resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==}
dependencies:
call-bind: 1.0.2
dev: true
/is-stream/2.0.1:
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
engines: {node: '>=8'}
dev: true
/is-string/1.0.7:
resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
engines: {node: '>= 0.4'}
dependencies:
has-tostringtag: 1.0.0
dev: true
/is-symbol/1.0.4:
resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==}
engines: {node: '>= 0.4'}
dependencies:
has-symbols: 1.0.3
dev: true
/is-weakref/1.0.2:
resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
dependencies:
call-bind: 1.0.2
dev: true
/is-windows/1.0.2:
resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==}
engines: {node: '>=0.10.0'}
@ -2481,14 +2153,6 @@ packages:
engines: {node: '>=14'}
dev: true
/locate-path/2.0.0:
resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==}
engines: {node: '>=4'}
dependencies:
p-locate: 2.0.0
path-exists: 3.0.0
dev: true
/lodash-es/4.17.21:
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
dev: false
@ -2561,10 +2225,6 @@ packages:
resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==}
dev: false
/memory-fs/0.2.0:
resolution: {integrity: sha512-+y4mDxU4rvXXu5UDSGCGNiesFmwCHuefGMoPCO1WYucNYj7DsLqrFaa2fXVI0H+NNiPTwwzKwspn9yTZqUGqng==}
dev: true
/merge-options/1.0.1:
resolution: {integrity: sha512-iuPV41VWKWBIOpBsjoxjDZw8/GbSfZ2mk7N1453bwMrfzdrIk7EzBd+8UVR6rkw67th7xnk9Dytl3J+lHPdxvg==}
engines: {node: '>=4'}
@ -2720,11 +2380,6 @@ packages:
resolution: {integrity: sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==}
dev: true
/object-keys/1.1.1:
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
engines: {node: '>= 0.4'}
dev: true
/object-visit/1.0.1:
resolution: {integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==}
engines: {node: '>=0.10.0'}
@ -2732,16 +2387,6 @@ packages:
isobject: 3.0.1
dev: true
/object.assign/4.1.2:
resolution: {integrity: sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
define-properties: 1.1.4
has-symbols: 1.0.3
object-keys: 1.1.1
dev: true
/object.pick/1.3.0:
resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==}
engines: {node: '>=0.10.0'}
@ -2749,15 +2394,6 @@ packages:
isobject: 3.0.1
dev: true
/object.values/1.1.5:
resolution: {integrity: sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
define-properties: 1.1.4
es-abstract: 1.19.5
dev: true
/once/1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
@ -2783,20 +2419,6 @@ packages:
word-wrap: 1.2.3
dev: true
/p-limit/1.3.0:
resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==}
engines: {node: '>=4'}
dependencies:
p-try: 1.0.0
dev: true
/p-locate/2.0.0:
resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==}
engines: {node: '>=4'}
dependencies:
p-limit: 1.3.0
dev: true
/p-map/4.0.0:
resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
engines: {node: '>=10'}
@ -2804,11 +2426,6 @@ packages:
aggregate-error: 3.1.0
dev: true
/p-try/1.0.0:
resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==}
engines: {node: '>=4'}
dev: true
/parent-module/1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
@ -2825,11 +2442,6 @@ packages:
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
dev: false
/path-exists/3.0.0:
resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==}
engines: {node: '>=4'}
dev: true
/path-is-absolute/1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
@ -2960,6 +2572,19 @@ packages:
engines: {node: '>= 0.8.0'}
dev: true
/prettier-linter-helpers/1.0.0:
resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
engines: {node: '>=6.0.0'}
dependencies:
fast-diff: 1.2.0
dev: true
/prettier/2.6.2:
resolution: {integrity: sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==}
engines: {node: '>=10.13.0'}
hasBin: true
dev: true
/punycode/2.1.1:
resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==}
engines: {node: '>=6'}
@ -3109,16 +2734,6 @@ packages:
engines: {node: ^14.13.1 || >=16.0.0}
dev: false
/semver/5.7.1:
resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==}
hasBin: true
dev: true
/semver/6.3.0:
resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
hasBin: true
dev: true
/semver/7.3.7:
resolution: {integrity: sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==}
engines: {node: '>=10'}
@ -3149,14 +2764,6 @@ packages:
engines: {node: '>=8'}
dev: true
/side-channel/1.0.4:
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
dependencies:
call-bind: 1.0.2
get-intrinsic: 1.1.1
object-inspect: 1.12.0
dev: true
/signal-exit/3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
dev: true
@ -3301,20 +2908,6 @@ packages:
strip-ansi: 7.0.1
dev: true
/string.prototype.trimend/1.0.4:
resolution: {integrity: sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==}
dependencies:
call-bind: 1.0.2
define-properties: 1.1.4
dev: true
/string.prototype.trimstart/1.0.4:
resolution: {integrity: sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==}
dependencies:
call-bind: 1.0.2
define-properties: 1.1.4
dev: true
/string_decoder/1.3.0:
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
dependencies:
@ -3342,11 +2935,6 @@ packages:
ansi-regex: 6.0.1
dev: true
/strip-bom/3.0.0:
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
engines: {node: '>=4'}
dev: true
/strip-final-newline/2.0.0:
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
engines: {node: '>=6'}
@ -3418,11 +3006,6 @@ packages:
stable: 0.1.8
dev: true
/tapable/0.1.10:
resolution: {integrity: sha512-jX8Et4hHg57mug1/079yitEKWGB3LCwoxByLsNim89LABq8NqgiX+6iYVOsq0vX8uJHkU+DZ5fnq95f800bEsQ==}
engines: {node: '>=0.6'}
dev: true
/text-table/0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
dev: true
@ -3467,15 +3050,6 @@ packages:
resolution: {integrity: sha512-kdf4JKs8lbARxWdp7RKdNzoJBhGUcIalSYibuGyHJbmk40pOysQ0+QPvlkCOICOivDWU2IJo2rkrxyTK2AH4fw==}
dev: true
/tsconfig-paths/3.14.1:
resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==}
dependencies:
'@types/json5': 0.0.29
json5: 1.0.1
minimist: 1.2.6
strip-bom: 3.0.0
dev: true
/tslib/1.14.1:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
dev: true
@ -3517,15 +3091,6 @@ packages:
hasBin: true
dev: true
/unbox-primitive/1.0.1:
resolution: {integrity: sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==}
dependencies:
function-bind: 1.1.1
has-bigints: 1.0.2
has-symbols: 1.0.3
which-boxed-primitive: 1.0.2
dev: true
/union-value/1.0.1:
resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==}
engines: {node: '>=0.10.0'}
@ -3769,16 +3334,6 @@ packages:
resolution: {integrity: sha512-5NUqC2JquIL2pBAAo/VfBP6KuGkHIZQXW/lNKupLPfhViwh8wNsu0BObtl09yuKZszeEUfbXz8xhrHvSG16Nqw==}
dev: true
/which-boxed-primitive/1.0.2:
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
dependencies:
is-bigint: 1.0.4
is-boolean-object: 1.1.2
is-number-object: 1.0.7
is-string: 1.0.7
is-symbol: 1.0.4
dev: true
/which/2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}

View File

@ -7,13 +7,13 @@ module.exports = {
/** 在对象中的括号之间用空格来间隔 */
bracketSpacing: true,
/** 箭头函数的参数无论有几个,都要括号包裹 */
arrowParens: 'always',
arrowParens: "always",
/** 换行符的使用 */
endOfLine: 'auto',
/** 采用单引号 */
singleQuote: true,
endOfLine: "auto",
/** 是否采用单引号 */
singleQuote: false,
/** 对象或者数组的最后一个元素后面不要加逗号 */
trailingComma: 'none',
trailingComma: "none",
/** 不加分号 */
semi: false,
/** 不使用 tab 格式化 */

View File

@ -5,9 +5,9 @@
</template>
<script lang="ts" setup>
import { ElConfigProvider } from 'element-plus'
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
import { useAppStore } from '@/store/modules/app'
import { ElConfigProvider } from "element-plus"
import zhCn from "element-plus/lib/locale/lang/zh-cn"
import { useAppStore } from "@/store/modules/app"
const locale = zhCn // element-plus

View File

@ -1,4 +1,4 @@
import { request } from '@/utils/service'
import { request } from "@/utils/service"
interface IUserRequestData {
username: string
@ -8,15 +8,15 @@ interface IUserRequestData {
/** 登录,返回 token */
export function accountLogin(data: IUserRequestData) {
return request({
url: 'users/login',
method: 'post',
url: "users/login",
method: "post",
data
})
}
/** 获取用户详情 */
export function userInfoRequest() {
return request({
url: 'users/info',
method: 'post'
url: "users/info",
method: "post"
})
}

View File

@ -9,13 +9,13 @@
</template>
<script lang="ts" setup>
import { FullScreen } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import screenfull from 'screenfull'
import { FullScreen } from "@element-plus/icons-vue"
import { ElMessage } from "element-plus"
import screenfull from "screenfull"
const click = () => {
if (!screenfull.isEnabled) {
ElMessage.warning('您的浏览器无法工作')
ElMessage.warning("您的浏览器无法工作")
return
}
screenfull.toggle()

View File

@ -5,12 +5,12 @@
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import { computed } from "vue"
const props = defineProps({
prefix: {
type: String,
default: 'icon'
default: "icon"
},
name: {
type: String,

View File

@ -21,9 +21,9 @@
</template>
<script lang="ts" setup>
import { MagicStick } from '@element-plus/icons-vue'
import { computed } from 'vue'
import { useAppStore } from '@/store/modules/app'
import { MagicStick } from "@element-plus/icons-vue"
import { computed } from "vue"
import { useAppStore } from "@/store/modules/app"
const appStore = useAppStore()
const themeList = computed(() => {

View File

@ -8,7 +8,7 @@ interface IRolesSettings {
const rolesSettings: IRolesSettings = {
openRoles: true,
defaultRoles: ['admin']
defaultRoles: ["admin"]
}
export default rolesSettings

View File

@ -1,12 +1,12 @@
/** 注册的主题 */
const themeList = [
{
title: '默认',
name: 'normal'
title: "默认",
name: "normal"
},
{
title: '黑暗',
name: 'dark'
title: "黑暗",
name: "dark"
}
]

View File

@ -1,4 +1,4 @@
/** 免登录白名单 */
const whiteList = ['/login']
const whiteList = ["/login"]
export { whiteList }

View File

@ -1,8 +1,8 @@
class Keys {
static sidebarStatus = 'v3-admin-sidebar-status-key'
static language = 'v3-admin-language-key'
static token = 'v3-admin-token-key'
static activeThemeName = 'v3-admin-active-theme-name'
static sidebarStatus = "v3-admin-sidebar-status-key"
static language = "v3-admin-language-key"
static token = "v3-admin-token-key"
static activeThemeName = "v3-admin-active-theme-name"
}
export default Keys

View File

@ -1 +1 @@
export * from './permission'
export * from "./permission"

View File

@ -1,5 +1,5 @@
import { useUserStoreHook } from '@/store/modules/user'
import { Directive } from 'vue'
import { useUserStoreHook } from "@/store/modules/user"
import { Directive } from "vue"
/** 权限指令 */
export const permission: Directive = {
@ -12,7 +12,7 @@ export const permission: Directive = {
return permissionRoles.includes(role)
})
if (!hasPermission) {
el.style.display = 'none'
el.style.display = "none"
}
} else {
throw new Error("need roles! Like v-permission=\"['admin','editor']\"")

View File

@ -1,7 +1,7 @@
import { createApp } from 'vue'
import SvgIcon from '@/components/SvgIcon/index.vue' // svg component
import 'virtual:svg-icons-register'
import { createApp } from "vue"
import SvgIcon from "@/components/SvgIcon/index.vue" // svg component
import "virtual:svg-icons-register"
export default (app: ReturnType<typeof createApp>) => {
app.component('SvgIcon', SvgIcon)
app.component("SvgIcon", SvgIcon)
}

View File

@ -1,7 +1,7 @@
<!-- 主视图 -->
<template>
<section class="app-main">
<router-view v-slot="{Component}">
<router-view v-slot="{ Component }">
<transition name="fade-transform" mode="out-in">
<!-- <keep-alive> -->
<component :is="Component" :key="key" />
@ -12,8 +12,8 @@
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import { computed } from "vue"
import { useRoute } from "vue-router"
const route = useRoute()
const key = computed(() => {

View File

@ -15,9 +15,9 @@
</template>
<script lang="ts" setup>
import { onBeforeMount, reactive, watch } from 'vue'
import { useRoute, useRouter, RouteLocationMatched } from 'vue-router'
import { compile } from 'path-to-regexp'
import { onBeforeMount, reactive, watch } from "vue"
import { useRoute, useRouter, RouteLocationMatched } from "vue-router"
import { compile } from "path-to-regexp"
const currentRoute = useRoute()
const router = useRouter()
@ -52,7 +52,7 @@ const state = reactive({
watch(
() => currentRoute.path,
(path) => {
if (path.startsWith('/redirect/')) {
if (path.startsWith("/redirect/")) {
return
}
state.getBreadcrumb()

View File

@ -9,7 +9,7 @@
</template>
<script lang="ts" setup>
import { Expand, Fold } from '@element-plus/icons-vue'
import { Expand, Fold } from "@element-plus/icons-vue"
defineProps({
isActive: {
@ -18,10 +18,10 @@ defineProps({
}
})
const emit = defineEmits(['toggle-click'])
const emit = defineEmits(["toggle-click"])
const toggleClick = () => {
emit('toggle-click')
emit("toggle-click")
}
</script>

View File

@ -36,16 +36,16 @@
</template>
<script lang="ts" setup>
import { UserFilled } from '@element-plus/icons-vue'
import { computed, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { useAppStore } from '@/store/modules/app'
import { useSettingsStore } from '@/store/modules/settings'
import { useUserStore } from '@/store/modules/user'
import BreadCrumb from '../BreadCrumb/index.vue'
import Hamburger from '../Hamburger/index.vue'
import ThemeSwitch from '@/components/ThemeSwitch/index.vue'
import Screenfull from '@/components/Screenfull/index.vue'
import { UserFilled } from "@element-plus/icons-vue"
import { computed, reactive } from "vue"
import { useRouter } from "vue-router"
import { useAppStore } from "@/store/modules/app"
import { useSettingsStore } from "@/store/modules/settings"
import { useUserStore } from "@/store/modules/user"
import BreadCrumb from "../BreadCrumb/index.vue"
import Hamburger from "../Hamburger/index.vue"
import ThemeSwitch from "@/components/ThemeSwitch/index.vue"
import Screenfull from "@/components/Screenfull/index.vue"
const router = useRouter()
const appStore = useAppStore()
@ -66,7 +66,7 @@ const state = reactive({
},
logout: () => {
userStore.logout()
router.push('/login').catch((err) => {
router.push("/login").catch((err) => {
console.warn(err)
})
}

View File

@ -1,6 +1,6 @@
<!-- 右侧悬浮设置面板 -->
<template>
<div class="handle-button" :style="{top: buttonTop + 'px'}" @click="show = true">
<div class="handle-button" :style="{ top: buttonTop + 'px' }" @click="show = true">
<el-icon :size="24">
<Setting />
</el-icon>
@ -11,8 +11,8 @@
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { Setting } from '@element-plus/icons-vue'
import { ref } from "vue"
import { Setting } from "@element-plus/icons-vue"
defineProps({
buttonTop: {

View File

@ -2,9 +2,7 @@
<template>
<div class="drawer-container">
<div>
<h3 class="drawer-title">
系统布局配置
</h3>
<h3 class="drawer-title">系统布局配置</h3>
<div class="drawer-item">
<span>显示 Tags-View</span>
<el-switch v-model="state.showTagsView" class="drawer-switch" />
@ -30,8 +28,8 @@
</template>
<script lang="ts" setup>
import { useSettingsStore } from '@/store/modules/settings'
import { reactive, watch } from 'vue'
import { useSettingsStore } from "@/store/modules/settings"
import { reactive, watch } from "vue"
const settingsStore = useSettingsStore()
@ -47,7 +45,7 @@ watch(
() => state.fixedHeader,
(value) => {
settingsStore.changeSetting({
key: 'fixedHeader',
key: "fixedHeader",
value
})
}
@ -57,7 +55,7 @@ watch(
() => state.showTagsView,
(value) => {
settingsStore.changeSetting({
key: 'showTagsView',
key: "showTagsView",
value
})
}
@ -67,7 +65,7 @@ watch(
() => state.showSidebarLogo,
(value) => {
settingsStore.changeSetting({
key: 'showSidebarLogo',
key: "showSidebarLogo",
value
})
}
@ -77,7 +75,7 @@ watch(
() => state.showThemeSwitch,
(value) => {
settingsStore.changeSetting({
key: 'showThemeSwitch',
key: "showThemeSwitch",
value
})
}
@ -87,7 +85,7 @@ watch(
() => state.showScreenfull,
(value) => {
settingsStore.changeSetting({
key: 'showScreenfull',
key: "showScreenfull",
value
})
}

View File

@ -1,6 +1,6 @@
<!-- 侧边栏 Item -->
<template>
<div v-if="!item.meta || !item.meta.hidden" :class="{'simple-mode': isCollapse, 'first-level': isFirstLevel}">
<div v-if="!item.meta || !item.meta.hidden" :class="{ 'simple-mode': isCollapse, 'first-level': isFirstLevel }">
<template v-if="!alwaysShowRootMenu && theOnlyOneChild && !theOnlyOneChild.children">
<SidebarItemLink v-if="theOnlyOneChild.meta" :to="resolvePath(theOnlyOneChild.path)">
<el-menu-item :index="resolvePath(theOnlyOneChild.path)">
@ -31,11 +31,11 @@
</template>
<script lang="ts" setup>
import path from 'path-browserify'
import { computed, PropType } from 'vue'
import { RouteRecordRaw } from 'vue-router'
import { isExternal } from '@/utils/validate'
import SidebarItemLink from './SidebarItemLink.vue'
import path from "path-browserify"
import { computed, PropType } from "vue"
import { RouteRecordRaw } from "vue-router"
import { isExternal } from "@/utils/validate"
import SidebarItemLink from "./SidebarItemLink.vue"
const props = defineProps({
item: {
@ -82,7 +82,7 @@ const theOnlyOneChild = computed(() => {
}
// If there is no children, return itself with path removed,
// because this.basePath already contains item's path information
return { ...props.item, path: '' }
return { ...props.item, path: "" }
})
const resolvePath = (routePath: string) => {

View File

@ -8,8 +8,8 @@
</template>
<script lang="ts" setup>
import { isExternal } from '@/utils/validate'
import { useRouter } from 'vue-router'
import { isExternal } from "@/utils/validate"
import { useRouter } from "vue-router"
const props = defineProps({
to: {

View File

@ -1,12 +1,12 @@
<!-- 侧边栏 Logo需要跟随侧边栏折叠 -->
<template>
<div class="sidebar-logo-container" :class="{collapse: collapse}">
<div class="sidebar-logo-container" :class="{ collapse: collapse }">
<transition name="sidebarLogoFade">
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
<img src="@/assets/layout/logo.png" class="sidebar-logo">
<img src="@/assets/layout/logo.png" class="sidebar-logo" />
</router-link>
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
<img src="@/assets/layout/logo-text-1.png" class="sidebar-logo-text">
<img src="@/assets/layout/logo-text-1.png" class="sidebar-logo-text" />
</router-link>
</transition>
</div>

View File

@ -1,5 +1,5 @@
<template>
<div :class="{'has-logo': showLogo}">
<div :class="{ 'has-logo': showLogo }">
<SidebarLogo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
@ -24,13 +24,13 @@
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import { useAppStore } from '@/store/modules/app'
import { usePermissionStore } from '@/store/modules/permission'
import { useSettingsStore } from '@/store/modules/settings'
import SidebarItem from './SidebarItem.vue'
import SidebarLogo from './SidebarLogo.vue'
import { computed } from "vue"
import { useRoute } from "vue-router"
import { useAppStore } from "@/store/modules/app"
import { usePermissionStore } from "@/store/modules/permission"
import { useSettingsStore } from "@/store/modules/settings"
import SidebarItem from "./SidebarItem.vue"
import SidebarLogo from "./SidebarLogo.vue"
const route = useRoute()
const sidebar = computed(() => {
@ -82,7 +82,7 @@ const isCollapse = computed(() => {
<style lang="scss" scoped>
@mixin tip-line {
&::before {
content: '';
content: "";
position: absolute;
top: 0;
left: 0;

View File

@ -6,7 +6,7 @@
ref="tag"
:key="tag.path"
:class="state.isActive(tag) ? 'active' : ''"
:to="{path: tag.path, query: tag.query, fullPath: tag.fullPath}"
:to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
class="tags-view-item"
@click.middle="!state.isAffix(tag) ? state.closeSelectedTag(tag) : ''"
@contextmenu.prevent="state.openMenu(tag, $event)"
@ -17,31 +17,23 @@
</el-icon>
</router-link>
</ScrollPane>
<ul v-show="state.visible" :style="{left: state.left + 'px', top: state.top + 'px'}" class="contextmenu">
<li @click="state.refreshSelectedTag(state.selectedTag)">
刷新
</li>
<li v-if="!state.isAffix(state.selectedTag)" @click="state.closeSelectedTag(state.selectedTag)">
关闭
</li>
<li @click="state.closeOthersTags">
关闭其它
</li>
<li @click="state.closeAllTags(state.selectedTag)">
关闭所有
</li>
<ul v-show="state.visible" :style="{ left: state.left + 'px', top: state.top + 'px' }" class="contextmenu">
<li @click="state.refreshSelectedTag(state.selectedTag)">刷新</li>
<li v-if="!state.isAffix(state.selectedTag)" @click="state.closeSelectedTag(state.selectedTag)">关闭</li>
<li @click="state.closeOthersTags">关闭其它</li>
<li @click="state.closeAllTags(state.selectedTag)">关闭所有</li>
</ul>
</div>
</template>
<script lang="ts" setup>
import path from 'path-browserify'
import { useTagsViewStore, ITagView } from '@/store/modules/tags-view'
import { usePermissionStore } from '@/store/modules/permission'
import { computed, getCurrentInstance, nextTick, onBeforeMount, reactive, watch } from 'vue'
import { RouteRecordRaw, useRoute, useRouter } from 'vue-router'
import ScrollPane from './ScrollPane.vue'
import { Close } from '@element-plus/icons-vue'
import path from "path-browserify"
import { useTagsViewStore, ITagView } from "@/store/modules/tags-view"
import { usePermissionStore } from "@/store/modules/permission"
import { computed, getCurrentInstance, nextTick, onBeforeMount, reactive, watch } from "vue"
import { RouteRecordRaw, useRoute, useRouter } from "vue-router"
import ScrollPane from "./ScrollPane.vue"
import { Close } from "@element-plus/icons-vue"
const tagsViewStore = useTagsViewStore()
const permissionStore = usePermissionStore()
@ -58,13 +50,13 @@ const toLastView = (visitedViews: ITagView[], view: ITagView) => {
})
} else {
// tags-view
if (view.name === 'Dashboard') {
if (view.name === "Dashboard") {
//
router.push({ path: '/redirect' + view.fullPath }).catch((err) => {
router.push({ path: "/redirect" + view.fullPath }).catch((err) => {
console.warn(err)
})
} else {
router.push('/').catch((err) => {
router.push("/").catch((err) => {
console.warn(err)
})
}
@ -86,7 +78,7 @@ const state = reactive({
refreshSelectedTag: (view: ITagView) => {
const { fullPath } = view
nextTick(() => {
router.replace({ path: '/redirect' + fullPath }).catch((err) => {
router.replace({ path: "/redirect" + fullPath }).catch((err) => {
console.warn(err)
})
})
@ -137,7 +129,7 @@ const visitedViews = computed(() => {
})
const routes = computed(() => permissionStore.routes)
const filterAffixTags = (routes: RouteRecordRaw[], basePath = '/') => {
const filterAffixTags = (routes: RouteRecordRaw[], basePath = "/") => {
let tags: ITagView[] = []
routes.forEach((route) => {
@ -205,9 +197,9 @@ watch(
() => state.visible,
(value) => {
if (value) {
document.body.addEventListener('click', state.closeMenu)
document.body.addEventListener("click", state.closeMenu)
} else {
document.body.removeEventListener('click', state.closeMenu)
document.body.removeEventListener("click", state.closeMenu)
}
}
)
@ -251,7 +243,7 @@ onBeforeMount(() => {
color: #fff;
border-color: #409eff;
&::before {
content: '';
content: "";
background: #fff;
display: inline-block;
width: 8px;

View File

@ -1,6 +1,6 @@
export { default as AppMain } from './AppMain.vue'
export { default as NavigationBar } from './NavigationBar/index.vue'
export { default as Settings } from './Settings/index.vue'
export { default as Sidebar } from './Sidebar/index.vue'
export { default as TagsView } from './TagsView/index.vue'
export { default as RightPanel } from './RightPanel/index.vue'
export { default as AppMain } from "./AppMain.vue"
export { default as NavigationBar } from "./NavigationBar/index.vue"
export { default as Settings } from "./Settings/index.vue"
export { default as Sidebar } from "./Sidebar/index.vue"
export { default as TagsView } from "./TagsView/index.vue"
export { default as RightPanel } from "./RightPanel/index.vue"

View File

@ -3,8 +3,8 @@
<div :class="classObj" class="app-wrapper">
<div v-if="classObj.mobile && sidebar.opened" class="drawer-bg" @click="state.handleClickOutside" />
<Sidebar class="sidebar-container" />
<div :class="{hasTagsView: showTagsView}" class="main-container">
<div :class="{'fixed-header': fixedHeader}">
<div :class="{ hasTagsView: showTagsView }" class="main-container">
<div :class="{ 'fixed-header': fixedHeader }">
<NavigationBar />
<TagsView v-if="showTagsView" />
</div>
@ -17,11 +17,11 @@
</template>
<script lang="ts" setup>
import { useAppStore, DeviceType } from '@/store/modules/app'
import { useSettingsStore } from '@/store/modules/settings'
import { computed, onBeforeMount, onBeforeUnmount, onMounted, reactive } from 'vue'
import { AppMain, NavigationBar, Settings, Sidebar, TagsView, RightPanel } from './components'
import useResize from './useResize'
import { useAppStore, DeviceType } from "@/store/modules/app"
import { useSettingsStore } from "@/store/modules/settings"
import { computed, onBeforeMount, onBeforeUnmount, onMounted, reactive } from "vue"
import { AppMain, NavigationBar, Settings, Sidebar, TagsView, RightPanel } from "./components"
import useResize from "./useResize"
const { sidebar, device, addEventListenerOnResize, resizeMounted, removeEventListenerResize, watchRouter } = useResize()
const appStore = useAppStore()
@ -64,7 +64,7 @@ onBeforeUnmount(() => {
</script>
<style lang="scss" scoped>
@import '@/styles/mixins.scss';
@import "@/styles/mixins.scss";
$sideBarWidth: 220px;
.app-wrapper {

View File

@ -1,12 +1,12 @@
import { useAppStore, DeviceType } from '@/store/modules/app'
import { computed, watch } from 'vue'
import { useRoute } from 'vue-router'
import { useAppStore, DeviceType } from "@/store/modules/app"
import { computed, watch } from "vue"
import { useRoute } from "vue-router"
/** 参考 Bootstrap 的响应式设计 width = 992 */
const WIDTH = 992
/** 根据大小变化重新布局 */
export default function() {
export default function () {
const appStore = useAppStore()
const device = computed(() => {
@ -50,11 +50,11 @@ export default function() {
}
const addEventListenerOnResize = () => {
window.addEventListener('resize', resizeHandler)
window.addEventListener("resize", resizeHandler)
}
const removeEventListenerResize = () => {
window.removeEventListener('resize', resizeHandler)
window.removeEventListener("resize", resizeHandler)
}
return {

View File

@ -1,12 +1,12 @@
import { createApp, Directive } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import '@/styles/index.scss'
import 'normalize.css'
import * as directives from '@/directives'
import '@/router/permission'
import loadSvg from '@/icons'
import { createApp, Directive } from "vue"
import App from "./App.vue"
import router from "./router"
import store from "./store"
import "@/styles/index.scss"
import "normalize.css"
import * as directives from "@/directives"
import "@/router/permission"
import loadSvg from "@/icons"
const app = createApp(App)
// 加载全局 SVG
@ -16,4 +16,4 @@ Object.keys(directives).forEach((key) => {
app.directive(key, (directives as { [key: string]: Directive })[key])
})
app.use(store).use(router).mount('#app')
app.use(store).use(router).mount("#app")

View File

@ -1,40 +1,40 @@
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
const Layout = () => import('@/layout/index.vue')
import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router"
const Layout = () => import("@/layout/index.vue")
/** 常驻路由 */
export const constantRoutes: Array<RouteRecordRaw> = [
{
path: '/redirect',
path: "/redirect",
component: Layout,
meta: {
hidden: true
},
children: [
{
path: '/redirect/:path(.*)',
component: () => import('@/views/redirect/index.vue')
path: "/redirect/:path(.*)",
component: () => import("@/views/redirect/index.vue")
}
]
},
{
path: '/login',
component: () => import('@/views/login/index.vue'),
path: "/login",
component: () => import("@/views/login/index.vue"),
meta: {
hidden: true
}
},
{
path: '/',
path: "/",
component: Layout,
redirect: '/dashboard',
redirect: "/dashboard",
children: [
{
path: 'dashboard',
component: () => import('@/views/dashboard/index.vue'),
name: 'Dashboard',
path: "dashboard",
component: () => import("@/views/dashboard/index.vue"),
name: "Dashboard",
meta: {
title: '首页',
icon: 'dashboard',
title: "首页",
icon: "dashboard",
affix: true
}
}
@ -49,61 +49,61 @@ export const constantRoutes: Array<RouteRecordRaw> = [
*/
export const asyncRoutes: Array<RouteRecordRaw> = [
{
path: '/permission',
path: "/permission",
component: Layout,
redirect: '/permission/page',
name: 'Permission',
redirect: "/permission/page",
name: "Permission",
meta: {
title: '权限管理',
icon: 'lock',
roles: ['admin', 'editor'], // 可以在根路由中设置角色
title: "权限管理",
icon: "lock",
roles: ["admin", "editor"], // 可以在根路由中设置角色
alwaysShow: true // 将始终显示根菜单
},
children: [
{
path: 'page',
component: () => import('@/views/permission/page.vue'),
name: 'PagePermission',
path: "page",
component: () => import("@/views/permission/page.vue"),
name: "PagePermission",
meta: {
title: '页面权限',
roles: ['admin'] // 或者在子导航中设置角色
title: "页面权限",
roles: ["admin"] // 或者在子导航中设置角色
}
},
{
path: 'directive',
component: () => import('@/views/permission/directive.vue'),
name: 'DirectivePermission',
path: "directive",
component: () => import("@/views/permission/directive.vue"),
name: "DirectivePermission",
meta: {
title: '指令权限' // 如果未设置角色,则表示:该页面不需要权限,但会继承根路由的角色
title: "指令权限" // 如果未设置角色,则表示:该页面不需要权限,但会继承根路由的角色
}
}
]
},
{
path: '/:pathMatch(.*)*', // 必须将 'ErrorPage' 路由放在最后, Must put the 'ErrorPage' route at the end
path: "/:pathMatch(.*)*", // 必须将 'ErrorPage' 路由放在最后, Must put the 'ErrorPage' route at the end
component: Layout,
redirect: '/404',
name: 'ErrorPage',
redirect: "/404",
name: "ErrorPage",
meta: {
title: '错误页面',
icon: '404',
title: "错误页面",
icon: "404",
hidden: true
},
children: [
{
path: '401',
component: () => import('@/views/error-page/401.vue'),
name: '401',
path: "401",
component: () => import("@/views/error-page/401.vue"),
name: "401",
meta: {
title: '401'
title: "401"
}
},
{
path: '404',
component: () => import('@/views/error-page/404.vue'),
name: '404',
path: "404",
component: () => import("@/views/error-page/404.vue"),
name: "404",
meta: {
title: '404'
title: "404"
}
}
]

View File

@ -1,25 +1,25 @@
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import router from '@/router'
import { RouteLocationNormalized } from 'vue-router'
import { useUserStoreHook } from '@/store/modules/user'
import { usePermissionStoreHook } from '@/store/modules/permission'
import { ElMessage } from 'element-plus'
import { whiteList } from '@/config/white-list'
import rolesSettings from '@/config/roles'
import { getToken } from '@/utils/cookies'
import NProgress from "nprogress"
import "nprogress/nprogress.css"
import router from "@/router"
import { RouteLocationNormalized } from "vue-router"
import { useUserStoreHook } from "@/store/modules/user"
import { usePermissionStoreHook } from "@/store/modules/permission"
import { ElMessage } from "element-plus"
import { whiteList } from "@/config/white-list"
import rolesSettings from "@/config/roles"
import { getToken } from "@/utils/cookies"
const userStore = useUserStoreHook()
const permissionStore = usePermissionStoreHook()
NProgress.configure({ showSpinner: false })
router.beforeEach(async(to: RouteLocationNormalized, _: RouteLocationNormalized, next: any) => {
router.beforeEach(async (to: RouteLocationNormalized, _: RouteLocationNormalized, next: any) => {
NProgress.start()
// 判断该用户是否登录
if (getToken()) {
if (to.path === '/login') {
if (to.path === "/login") {
// 如果登录,并准备进入 login 页面,则重定向到主页
next({ path: '/' })
next({ path: "/" })
NProgress.done()
} else {
// 检查用户是否已获得其权限角色
@ -47,8 +47,8 @@ router.beforeEach(async(to: RouteLocationNormalized, _: RouteLocationNormalized,
} catch (err: any) {
// 删除 token并重定向到登录页面
userStore.resetToken()
ElMessage.error(err.message || 'Has Error')
next('/login')
ElMessage.error(err.message || "Has Error")
next("/login")
NProgress.done()
}
} else {
@ -62,7 +62,7 @@ router.beforeEach(async(to: RouteLocationNormalized, _: RouteLocationNormalized,
next()
} else {
// 其他没有访问权限的页面将被重定向到登录页面
next('/login')
next("/login")
NProgress.done()
}
}

View File

@ -1,4 +1,4 @@
import { createPinia } from 'pinia'
import { createPinia } from "pinia"
const store = createPinia()

View File

@ -1,6 +1,6 @@
import { defineStore } from 'pinia'
import { getSidebarStatus, getActiveThemeName, setSidebarStatus, setActiveThemeName } from '@/utils/cookies'
import themeList from '@/config/theme'
import { defineStore } from "pinia"
import { getSidebarStatus, getActiveThemeName, setSidebarStatus, setActiveThemeName } from "@/utils/cookies"
import themeList from "@/config/theme"
export enum DeviceType {
Mobile,
@ -14,22 +14,22 @@ interface IAppState {
withoutAnimation: boolean
}
/** 主题列表 */
themeList: { title: string, name: string }[]
themeList: { title: string; name: string }[]
/** 正在应用的主题的名字 */
activeThemeName: string
}
export const useAppStore = defineStore({
id: 'app',
id: "app",
state: (): IAppState => {
return {
device: DeviceType.Desktop,
sidebar: {
opened: getSidebarStatus() !== 'closed',
opened: getSidebarStatus() !== "closed",
withoutAnimation: false
},
themeList: themeList,
activeThemeName: getActiveThemeName() || 'normal'
activeThemeName: getActiveThemeName() || "normal"
}
},
actions: {
@ -37,15 +37,15 @@ export const useAppStore = defineStore({
this.sidebar.opened = !this.sidebar.opened
this.sidebar.withoutAnimation = withoutAnimation
if (this.sidebar.opened) {
setSidebarStatus('opened')
setSidebarStatus("opened")
} else {
setSidebarStatus('closed')
setSidebarStatus("closed")
}
},
closeSidebar(withoutAnimation: boolean) {
this.sidebar.opened = false
this.sidebar.withoutAnimation = withoutAnimation
setSidebarStatus('closed')
setSidebarStatus("closed")
},
toggleDevice(device: DeviceType) {
this.device = device

View File

@ -1,7 +1,7 @@
import store from '@/store'
import { defineStore } from 'pinia'
import { RouteRecordRaw } from 'vue-router'
import { constantRoutes, asyncRoutes } from '@/router'
import store from "@/store"
import { defineStore } from "pinia"
import { RouteRecordRaw } from "vue-router"
import { constantRoutes, asyncRoutes } from "@/router"
interface IPermissionState {
routes: RouteRecordRaw[]
@ -37,7 +37,7 @@ const filterAsyncRoutes = (routes: RouteRecordRaw[], roles: string[]) => {
}
export const usePermissionStore = defineStore({
id: 'permission',
id: "permission",
state: (): IPermissionState => {
return {
routes: [],
@ -47,7 +47,7 @@ export const usePermissionStore = defineStore({
actions: {
setRoutes(roles: string[]) {
let accessedRoutes
if (roles.includes('admin')) {
if (roles.includes("admin")) {
accessedRoutes = asyncRoutes
} else {
accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)

View File

@ -1,5 +1,5 @@
import { defineStore } from 'pinia'
import layoutSettings from '@/config/layout'
import { defineStore } from "pinia"
import layoutSettings from "@/config/layout"
interface ISettingsState {
fixedHeader: boolean
@ -11,7 +11,7 @@ interface ISettingsState {
}
export const useSettingsStore = defineStore({
id: 'settings',
id: "settings",
state: (): ISettingsState => {
return {
fixedHeader: layoutSettings.fixedHeader,
@ -23,25 +23,25 @@ export const useSettingsStore = defineStore({
}
},
actions: {
changeSetting(payload: { key: string, value: any }) {
changeSetting(payload: { key: string; value: any }) {
const { key, value } = payload
switch (key) {
case 'fixedHeader':
case "fixedHeader":
this.fixedHeader = value
break
case 'showSettings':
case "showSettings":
this.showSettings = value
break
case 'showSidebarLogo':
case "showSidebarLogo":
this.showSidebarLogo = value
break
case 'showTagsView':
case "showTagsView":
this.showTagsView = value
break
case 'showThemeSwitch':
case "showThemeSwitch":
this.showThemeSwitch = value
break
case 'showScreenfull':
case "showScreenfull":
this.showScreenfull = value
break
default:

View File

@ -1,5 +1,5 @@
import { defineStore } from 'pinia'
import { _RouteLocationBase, RouteLocationNormalized } from 'vue-router'
import { defineStore } from "pinia"
import { _RouteLocationBase, RouteLocationNormalized } from "vue-router"
export interface ITagView extends Partial<RouteLocationNormalized> {
title?: string
@ -11,7 +11,7 @@ interface ITagsViewState {
}
export const useTagsViewStore = defineStore({
id: 'tags-view',
id: "tags-view",
state: (): ITagsViewState => {
return {
visitedViews: []
@ -22,7 +22,7 @@ export const useTagsViewStore = defineStore({
if (this.visitedViews.some((v) => v.path === view.path)) return
this.visitedViews.push(
Object.assign({}, view, {
title: view.meta?.title || 'no-name'
title: view.meta?.title || "no-name"
})
)
},

View File

@ -1,10 +1,10 @@
import store from '@/store'
import { defineStore } from 'pinia'
import { usePermissionStore } from './permission'
import { getToken, removeToken, setToken } from '@/utils/cookies'
import router, { resetRouter } from '@/router'
import { accountLogin, userInfoRequest } from '@/api/login'
import { RouteRecordRaw } from 'vue-router'
import store from "@/store"
import { defineStore } from "pinia"
import { usePermissionStore } from "./permission"
import { getToken, removeToken, setToken } from "@/utils/cookies"
import router, { resetRouter } from "@/router"
import { accountLogin, userInfoRequest } from "@/api/login"
import { RouteRecordRaw } from "vue-router"
interface IUserState {
token: string
@ -12,10 +12,10 @@ interface IUserState {
}
export const useUserStore = defineStore({
id: 'user',
id: "user",
state: (): IUserState => {
return {
token: getToken() || '',
token: getToken() || "",
roles: []
}
},
@ -25,7 +25,7 @@ export const useUserStore = defineStore({
this.roles = roles
},
/** 登录 */
login(userInfo: { username: string, password: string }) {
login(userInfo: { username: string; password: string }) {
return new Promise((resolve, reject) => {
accountLogin({
username: userInfo.username.trim(),
@ -56,7 +56,7 @@ export const useUserStore = defineStore({
},
/** 切换角色 */
async changeRoles(role: string) {
const token = role + '-token'
const token = role + "-token"
this.token = token
setToken(token)
await this.getInfo()
@ -70,14 +70,14 @@ export const useUserStore = defineStore({
/** 登出 */
logout() {
removeToken()
this.token = ''
this.token = ""
this.roles = []
resetRouter()
},
/** 重置 token */
resetToken() {
removeToken()
this.token = ''
this.token = ""
this.roles = []
}
}

View File

@ -1,6 +1,6 @@
@import './mixins.scss'; // mixins
@import './transition.scss'; // transition
@import './theme/register.scss'; // 注册主题
@import "./mixins.scss"; // mixins
@import "./transition.scss"; // transition
@import "./theme/register.scss"; // 注册主题
.app-container {
padding: 20px;
@ -15,7 +15,7 @@ body {
background-color: #f0f2f5; // 全局背景色
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial,
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial,
sans-serif;
}

View File

@ -1,6 +1,6 @@
@mixin clearfix {
&:after {
content: '';
content: "";
display: table;
clear: both;
}

View File

@ -1,2 +1,2 @@
@import './setting.scss';
@import '../theme.scss';
@import "./setting.scss";
@import "../theme.scss";

View File

@ -1,5 +1,5 @@
// 主题名称
$theme-name: 'dark';
$theme-name: "dark";
// 主题背景颜色
$theme-bg-color: #151515;
// active 状态下主题背景颜色

View File

@ -1,2 +1,2 @@
// 注册的主题
@import '@/styles/theme/dark/index.scss';
@import "@/styles/theme/dark/index.scss";

View File

@ -1,39 +0,0 @@
// generated by unplugin-vue-components
// We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/vue-next/pull/3399
import '@vue/runtime-core'
declare module '@vue/runtime-core' {
export interface GlobalComponents {
ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
ElButton: typeof import('element-plus/es')['ElButton']
ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElInput: typeof import('element-plus/es')['ElInput']
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Screenfull: typeof import('./../components/Screenfull/index.vue')['default']
SvgIcon: typeof import('./../components/SvgIcon/index.vue')['default']
ThemeSwitch: typeof import('./../components/ThemeSwitch/index.vue')['default']
}
}
export {}

10
src/types/index.d.ts vendored
View File

@ -1,10 +0,0 @@
/** 项目类型声明 */
declare module '*.svg'
declare module '*.png'
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.gif'
declare module '*.bmp'
declare module '*.tiff'
declare module '*.yaml'
declare module '*.json'

View File

@ -1,15 +0,0 @@
/** 声明自动引入的 vue 组件 */
declare module '*.vue' {
import { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
declare module '*.gif' {
export const gif: any
}
declare module '*.svg' {
const content: any
export default content
}

View File

@ -1,7 +1,7 @@
/** cookies 封装 */
import Keys from '@/constant/key'
import Cookies from 'js-cookie'
import Keys from "@/constant/key"
import Cookies from "js-cookie"
export const getSidebarStatus = () => Cookies.get(Keys.sidebarStatus)
export const setSidebarStatus = (sidebarStatus: string) => Cookies.set(Keys.sidebarStatus, sidebarStatus)

View File

@ -1,10 +1,10 @@
import dayjs from 'dayjs'
import dayjs from "dayjs"
/** 格式化时间 */
export const formatDateTime = (time: any) => {
if (time == null || time === '') {
return 'N/A'
if (time == null || time === "") {
return "N/A"
}
const date = new Date(time)
return dayjs(date).format('YYYY-MM-DD HH:mm:ss')
return dayjs(date).format("YYYY-MM-DD HH:mm:ss")
}

View File

@ -1,4 +1,4 @@
import { useUserStoreHook } from '@/store/modules/user'
import { useUserStoreHook } from "@/store/modules/user"
/** 全局权限判断函数,和指令 v-permission 功能类似 */
export const checkPermission = (value: string[]): boolean => {

View File

@ -1,8 +1,8 @@
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'
import { get } from 'lodash-es'
import { ElMessage } from 'element-plus'
import { getToken } from '@/utils/cookies'
import { useUserStoreHook } from '@/store/modules/user'
import axios, { AxiosInstance, AxiosRequestConfig } from "axios"
import { get } from "lodash-es"
import { ElMessage } from "element-plus"
import { getToken } from "@/utils/cookies"
import { useUserStoreHook } from "@/store/modules/user"
/** 创建请求实例 */
function createService() {
@ -23,8 +23,8 @@ function createService() {
const code = apiData.code
// 如果没有 code, 代表这不是项目后端开发的 api
if (code === undefined) {
ElMessage.error('非本系统的接口')
return Promise.reject(new Error('非本系统的接口'))
ElMessage.error("非本系统的接口")
return Promise.reject(new Error("非本系统的接口"))
} else {
switch (code) {
case 0:
@ -35,20 +35,20 @@ function createService() {
return apiData
default:
// 不是正确的 code
ElMessage.error(apiData.msg || 'Error')
return Promise.reject(new Error('Error'))
ElMessage.error(apiData.msg || "Error")
return Promise.reject(new Error("Error"))
}
}
},
(error) => {
// status 是 HTTP 状态码
const status = get(error, 'response.status')
const status = get(error, "response.status")
switch (status) {
case 400:
error.message = '请求错误'
error.message = "请求错误"
break
case 401:
error.message = '未授权,请登录'
error.message = "未授权,请登录"
break
case 403:
// token 过期时,直接退出登录并强制刷新页面(会重定向到登录页)
@ -56,28 +56,28 @@ function createService() {
location.reload()
break
case 404:
error.message = '请求地址出错'
error.message = "请求地址出错"
break
case 408:
error.message = '请求超时'
error.message = "请求超时"
break
case 500:
error.message = '服务器内部错误'
error.message = "服务器内部错误"
break
case 501:
error.message = '服务未实现'
error.message = "服务未实现"
break
case 502:
error.message = '网关错误'
error.message = "网关错误"
break
case 503:
error.message = '服务不可用'
error.message = "服务不可用"
break
case 504:
error.message = '网关超时'
error.message = "网关超时"
break
case 505:
error.message = 'HTTP版本不受支持'
error.message = "HTTP版本不受支持"
break
default:
break
@ -91,12 +91,12 @@ function createService() {
/** 创建请求方法 */
function createRequestFunction(service: AxiosInstance) {
return function(config: AxiosRequestConfig) {
return function (config: AxiosRequestConfig) {
const configDefault = {
headers: {
// 携带 token
'X-Access-Token': getToken(),
'Content-Type': get(config, 'headers.Content-Type', 'application/json')
"X-Access-Token": getToken(),
"Content-Type": get(config, "headers.Content-Type", "application/json")
},
timeout: 5000,
baseURL: import.meta.env.VITE_BASE_API,

View File

@ -1,8 +1,8 @@
export const isExternal = (path: string) => /^(https?:|mailto:|tel:)/.test(path)
export const isArray = (arg: any) => {
if (typeof Array.isArray === 'undefined') {
return Object.prototype.toString.call(arg) === '[object Array]'
if (typeof Array.isArray === "undefined") {
return Object.prototype.toString.call(arg) === "[object Array]"
}
return Array.isArray(arg)
}

View File

@ -1,6 +1,4 @@
<!-- admin 权限主页 -->
<template>
<div class="app-container">
Admin 权限可见
</div>
<div class="app-container">Admin 权限可见</div>
</template>

View File

@ -1,6 +1,4 @@
<!-- editor 权限主页 -->
<template>
<div class="app-container">
Editor 权限可见
</div>
<div class="app-container">Editor 权限可见</div>
</template>

View File

@ -3,18 +3,18 @@
</template>
<script lang="ts" setup>
import { useUserStore } from '@/store/modules/user'
import { computed, onBeforeMount, ref } from 'vue'
import AdminDashboard from './admin/index.vue'
import EditorDashboard from './editor/index.vue'
import { useUserStore } from "@/store/modules/user"
import { computed, onBeforeMount, ref } from "vue"
import AdminDashboard from "./admin/index.vue"
import EditorDashboard from "./editor/index.vue"
const currentRole = ref('admin')
const currentRole = ref("admin")
const roles = computed(() => {
return useUserStore().roles
})
onBeforeMount(() => {
if (!roles.value.includes('admin')) {
currentRole.value = 'editor'
if (!roles.value.includes("admin")) {
currentRole.value = "editor"
}
})
</script>

View File

@ -1,10 +1,6 @@
<template>
<div>
<p style="text-align: center; font-size: 140px; margin-bottom: 50px">
401
</p>
<p style="text-align: center; font-size: 40px">
你没有权限去该页面
</p>
<p style="text-align: center; font-size: 140px; margin-bottom: 50px">401</p>
<p style="text-align: center; font-size: 40px">你没有权限去该页面</p>
</div>
</template>

View File

@ -1,10 +1,6 @@
<template>
<div>
<p style="text-align: center; font-size: 140px; margin-bottom: 50px">
404
</p>
<p style="text-align: center; font-size: 40px">
未找到你想要的页面
</p>
<p style="text-align: center; font-size: 140px; margin-bottom: 50px">404</p>
<p style="text-align: center; font-size: 40px">未找到你想要的页面</p>
</div>
</template>

View File

@ -3,7 +3,7 @@
<ThemeSwitch class="theme-switch" />
<div class="login-card">
<div class="title">
<img src="@/assets/layout/logo-text-2.png">
<img src="@/assets/layout/logo-text-2.png" />
</div>
<div class="content">
<el-form ref="loginFormDom" :model="loginForm" :rules="loginRules" @keyup.enter="handleLogin">
@ -38,12 +38,10 @@
size="large"
/>
<span class="show-code">
<img :src="codeUrl" @click="createCode">
<img :src="codeUrl" @click="createCode" />
</span>
</el-form-item>
<el-button :loading="loading" type="primary" size="large" @click.prevent="handleLogin">
</el-button>
<el-button :loading="loading" type="primary" size="large" @click.prevent="handleLogin"> </el-button>
</el-form>
</div>
</div>
@ -51,11 +49,11 @@
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import { useUserStore } from '@/store/modules/user'
import { useRouter } from 'vue-router'
import { User, Lock, Key } from '@element-plus/icons-vue'
import ThemeSwitch from '@/components/ThemeSwitch/index.vue'
import { reactive, ref } from "vue"
import { useUserStore } from "@/store/modules/user"
import { useRouter } from "vue-router"
import { User, Lock, Key } from "@element-plus/icons-vue"
import ThemeSwitch from "@/components/ThemeSwitch/index.vue"
interface ILoginForm {
/** admin 或 editor */
@ -72,20 +70,20 @@ const router = useRouter()
const loading = ref<boolean>(false)
const loginFormDom = ref<any>()
const codeUrl = ref<string>('')
const codeUrl = ref<string>("")
const loginForm = reactive<ILoginForm>({
username: 'admin',
password: '123456',
code: '1234',
codeToken: ''
username: "admin",
password: "123456",
code: "1234",
codeToken: ""
})
const loginRules = reactive({
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 18, message: '长度在 6 到 18 个字符', trigger: 'blur' }
{ required: true, message: "请输入密码", trigger: "blur" },
{ min: 6, max: 18, message: "长度在 6 到 18 个字符", trigger: "blur" }
],
code: [{ required: true, message: '请输入验证码', trigger: 'blur' }]
code: [{ required: true, message: "请输入验证码", trigger: "blur" }]
})
const handleLogin = () => {
loginFormDom.value.validate((valid: boolean) => {
@ -98,7 +96,7 @@ const handleLogin = () => {
})
.then(() => {
loading.value = false
router.push({ path: '/' }).catch((err) => {
router.push({ path: "/" }).catch((err) => {
console.warn(err)
})
})
@ -114,51 +112,13 @@ const handleLogin = () => {
/** 创建验证码 */
const createCode: () => void = () => {
//
loginForm.code = ''
let codeToken = ''
const codeLength = 12
loginForm.code = ""
let codeToken = ""
const codeTokenLength = 12
//
const random: Array<number | string> = [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z'
]
for (let i = 0; i < codeLength; i++) {
for (let i = 0; i < codeTokenLength; i++) {
const index = Math.floor(Math.random() * 36)
codeToken += random[index]
codeToken += index
}
loginForm.codeToken = codeToken
//

View File

@ -1,9 +1,7 @@
<!-- 切换角色 -->
<template>
<div>
<div style="margin-bottom: 15px">
你的权限{{ roles }}
</div>
<div style="margin-bottom: 15px">你的权限{{ roles }}</div>
<div style="display: flex; align-items: center">
<span>切换权限</span>
<el-radio-group v-model="currentRole">
@ -15,15 +13,15 @@
</template>
<script lang="ts" setup>
import { useUserStore } from '@/store/modules/user'
import { computed, ref, watch } from 'vue'
import { useUserStore } from "@/store/modules/user"
import { computed, ref, watch } from "vue"
const userStore = useUserStore()
const emit = defineEmits(['change'])
const emit = defineEmits(["change"])
const roles = computed(() => userStore.roles)
const currentRole = ref(roles.value[0])
watch(currentRole, async(value) => {
watch(currentRole, async (value) => {
await userStore.changeRoles(value)
emit('change')
emit("change")
})
</script>

View File

@ -39,23 +39,17 @@
<el-tabs type="border-card" style="width: 550px; margin-top: 60px">
<el-tab-pane v-if="checkPermission(['admin'])" label="admin">
admin 可以看见这个
<el-tag class="permission-sourceCode" type="info">
v-if="checkPermission(['admin'])"
</el-tag>
<el-tag class="permission-sourceCode" type="info"> v-if="checkPermission(['admin'])" </el-tag>
</el-tab-pane>
<el-tab-pane v-if="checkPermission(['editor'])" label="editor">
editor 可以看见这个
<el-tag class="permission-sourceCode" type="info">
v-if="checkPermission(['editor'])"
</el-tag>
<el-tag class="permission-sourceCode" type="info"> v-if="checkPermission(['editor'])" </el-tag>
</el-tab-pane>
<el-tab-pane v-if="checkPermission(['admin', 'editor'])" label="admin 和 editor">
两者 admin editor 都可以看见这个
<el-tag class="permission-sourceCode" type="info">
v-if="checkPermission(['admin', 'editor'])"
</el-tag>
<el-tag class="permission-sourceCode" type="info"> v-if="checkPermission(['admin', 'editor'])" </el-tag>
</el-tab-pane>
</el-tabs>
</div>
@ -63,9 +57,9 @@
</template>
<script lang="ts" setup>
import { reactive } from 'vue'
import { checkPermission } from '@/utils/permission' //
import SwitchRoles from './components/switch-roles.vue'
import { reactive } from "vue"
import { checkPermission } from "@/utils/permission" //
import SwitchRoles from "./components/switch-roles.vue"
const state = reactive({
key: 1,

View File

@ -1,20 +1,18 @@
<!-- 页面权限测试页 -->
<template>
<div class="app-container">
<el-tag type="success" size="large" style="margin-bottom: 15px">
当前页面只有 admin 权限可见
</el-tag>
<el-tag type="success" size="large" style="margin-bottom: 15px"> 当前页面只有 admin 权限可见 </el-tag>
<SwitchRoles @change="handleRolesChange" />
</div>
</template>
<script lang="ts" setup>
import { useRouter } from 'vue-router'
import SwitchRoles from './components/switch-roles.vue'
import { useRouter } from "vue-router"
import SwitchRoles from "./components/switch-roles.vue"
const router = useRouter()
const handleRolesChange = () => {
router.push({ path: '/401' }).catch((err) => {
router.push({ path: "/401" }).catch((err) => {
console.warn(err)
})
}

View File

@ -4,12 +4,12 @@
</template>
<script lang="ts" setup>
import { useRoute, useRouter } from 'vue-router'
import { useRoute, useRouter } from "vue-router"
const { params, query } = useRoute()
const { path } = params
useRouter()
.replace({ path: '/' + path, query })
.replace({ path: "/" + path, query })
.catch((err) => {
console.warn(err)
})

16
types/components.d.ts vendored Normal file
View File

@ -0,0 +1,16 @@
// generated by unplugin-vue-components
// We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/vue-next/pull/3399
import '@vue/runtime-core'
declare module '@vue/runtime-core' {
export interface GlobalComponents {
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Screenfull: typeof import('./../src/components/Screenfull/index.vue')['default']
SvgIcon: typeof import('./../src/components/SvgIcon/index.vue')['default']
ThemeSwitch: typeof import('./../src/components/ThemeSwitch/index.vue')['default']
}
}
export {}

9
types/shims-app.d.ts vendored Normal file
View File

@ -0,0 +1,9 @@
declare module "*.svg"
declare module "*.png"
declare module "*.jpg"
declare module "*.jpeg"
declare module "*.gif"
declare module "*.bmp"
declare module "*.tiff"
declare module "*.yaml"
declare module "*.json"

19
types/shims-vue.d.ts vendored Normal file
View File

@ -0,0 +1,19 @@
declare module "*.vue" {
import { DefineComponent } from "vue"
const component: DefineComponent<{}, {}, any>
export default component
}
declare module "*.gif" {
export const gif: any
}
declare module "*.svg" {
const content: any
export default content
}
declare module "*.scss" {
const scss: Record<string, string>
export default scss
}

View File

@ -1,12 +1,12 @@
import { ElMessage } from 'element-plus'
import { ElMessage } from "element-plus"
declare module '@vue/runtime-core' {
declare module "@vue/runtime-core" {
interface ComponentCustomProperties {
$message: ElMessage
}
}
declare module 'vue-router' {
declare module "vue-router" {
interface RouteMeta {
roles?: string[]
activeMenu?: string

View File

@ -1,20 +1,20 @@
import { UserConfigExport } from 'vite'
import path, { resolve } from 'path'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import { UserConfigExport } from "vite"
import path, { resolve } from "path"
import vue from "@vitejs/plugin-vue"
import AutoImport from "unplugin-auto-import/vite"
import Components from "unplugin-vue-components/vite"
import { ElementPlusResolver } from "unplugin-vue-components/resolvers"
import { createSvgIconsPlugin } from "vite-plugin-svg-icons"
/** 配置项文档https://vitejs.dev/config */
export default (): UserConfigExport => {
return {
/** build 打包时根据实际情况修改 base */
base: '/',
base: "/",
resolve: {
alias: {
/** @ 符号指向 src 目录 */
'@': resolve(__dirname, './src')
"@": resolve(__dirname, "./src")
}
},
server: {
@ -32,12 +32,12 @@ export default (): UserConfigExport => {
strictPort: true,
/** 接口代理 */
proxy: {
'/mock-api': {
target: 'https://vue-typescript-admin-mock-server-armour.vercel.app/mock-api',
"/mock-api": {
target: "https://vue-typescript-admin-mock-server-armour.vercel.app/mock-api",
ws: true,
/** 是否允许跨域 */
changeOrigin: true,
rewrite: (path) => path.replace('/mock-api', '')
rewrite: (path) => path.replace("/mock-api", "")
}
}
},
@ -46,26 +46,26 @@ export default (): UserConfigExport => {
/** 消除打包大小超过 500kb 警告 */
chunkSizeWarningLimit: 2000,
/** vite 2.6.x 以上需要配置 minify: terserterserOptions 才能生效 */
minify: 'terser',
minify: "terser",
/** 在 build 代码时移除 console.log、debugger 和 注释 */
terserOptions: {
compress: {
drop_console: false,
drop_debugger: true,
pure_funcs: ['console.log']
pure_funcs: ["console.log"]
},
output: {
/** 删除注释 */
comments: false
}
},
assetsDir: 'static/assets',
assetsDir: "static/assets",
/** 静态资源打包到 dist 下的不同目录 */
rollupOptions: {
output: {
chunkFileNames: 'static/js/[name]-[hash].js',
entryFileNames: 'static/js/[name]-[hash].js',
assetFileNames: 'static/[ext]/[name]-[hash].[ext]'
chunkFileNames: "static/js/[name]-[hash].js",
entryFileNames: "static/js/[name]-[hash].js",
assetFileNames: "static/[ext]/[name]-[hash].[ext]"
}
}
},
@ -74,18 +74,18 @@ export default (): UserConfigExport => {
vue(),
/** 自动按需导入 */
AutoImport({
dts: './src/types/auto-imports.d.ts',
dts: "./types/auto-imports.d.ts",
resolvers: [ElementPlusResolver()]
}),
/** 自动按需导入 */
Components({
dts: './src/types/components.d.ts',
dts: "./types/components.d.ts",
resolvers: [ElementPlusResolver()]
}),
/** svg */
createSvgIconsPlugin({
iconDirs: [path.resolve(process.cwd(), 'src/icons/svg')],
symbolId: 'icon-[dir]-[name]'
iconDirs: [path.resolve(process.cwd(), "src/icons/svg")],
symbolId: "icon-[dir]-[name]"
})
]
}