From b93b80cb4b35268dfb6a09517a2494af24748dac Mon Sep 17 00:00:00 2001 From: Soybean Date: Wed, 5 Jan 2022 01:35:32 +0800 Subject: [PATCH] =?UTF-8?q?feat(projects):=20=E8=BF=81=E7=A7=BB=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mock/api/auth.ts | 55 ++- mock/api/route.ts | 2 +- package.json | 10 +- pnpm-lock.yaml | 350 +++++++++++------- src/AppProvider.vue | 2 +- .../business/LoginAgreement/index.vue | 48 +++ src/components/business/index.ts | 3 + .../common/DarkModeSwitch/index.vue | 39 ++ src/components/common/index.ts | 3 +- src/components/custom/ImageVerify/index.vue | 39 ++ src/components/custom/index.ts | 3 + src/components/index.ts | 2 + src/composables/common/index.ts | 2 + src/composables/common/route.ts | 32 ++ src/composables/common/router.ts | 90 +++++ src/config/common/index.ts | 1 + src/config/common/regexp.ts | 16 + src/hooks/business/index.ts | 5 + src/hooks/business/useCountDown.ts | 52 +++ src/hooks/business/useImageVerify.ts | 85 +++++ src/hooks/business/useSmsCode.ts | 59 +++ src/hooks/index.ts | 1 + src/interface/enum.ts | 2 - src/router/guard/permission.ts | 2 +- src/router/routes/constant.ts | 11 +- src/service/api/auth.ts | 32 +- src/service/middleware/auth.ts | 2 +- src/service/request/request.ts | 207 ++++++++--- src/store/modules/auth/index.ts | 89 ++++- src/store/modules/route/index.ts | 2 +- src/store/modules/theme/helpers.ts | 24 ++ src/store/modules/theme/index.ts | 59 ++- src/typings/api/auth.d.ts | 10 + src/typings/api/route.d.ts | 2 +- src/typings/business/auth.d.ts | 22 +- src/typings/common/route.d.ts | 9 +- src/typings/common/util.d.ts | 2 - src/utils/auth/user.ts | 3 +- src/utils/common/index.ts | 1 + src/utils/common/number.ts | 23 ++ src/utils/form/index.ts | 1 + src/utils/form/rule.ts | 73 ++++ src/utils/index.ts | 1 + src/utils/router/helpers.ts | 12 +- .../login/components/BindWechat/index.vue | 61 +++ .../login/components/CodeLogin/index.vue | 81 ++++ .../system/login/components/LoginBg/index.vue | 2 +- .../PwdLogin/components/OtherLogin.vue | 15 + .../components/PwdLogin/components/index.ts | 3 + .../login/components/PwdLogin/index.vue | 75 ++++ .../login/components/Register/index.vue | 75 ++++ .../login/components/ResetPwd/index.vue | 71 ++++ src/views/system/login/components/index.ts | 7 +- src/views/system/login/index.vue | 61 ++- 54 files changed, 1679 insertions(+), 260 deletions(-) create mode 100644 src/components/business/LoginAgreement/index.vue create mode 100644 src/components/business/index.ts create mode 100644 src/components/common/DarkModeSwitch/index.vue create mode 100644 src/components/custom/ImageVerify/index.vue create mode 100644 src/components/custom/index.ts create mode 100644 src/composables/common/route.ts create mode 100644 src/composables/common/router.ts create mode 100644 src/config/common/regexp.ts create mode 100644 src/hooks/business/index.ts create mode 100644 src/hooks/business/useCountDown.ts create mode 100644 src/hooks/business/useImageVerify.ts create mode 100644 src/hooks/business/useSmsCode.ts create mode 100644 src/typings/api/auth.d.ts create mode 100644 src/utils/common/number.ts create mode 100644 src/utils/form/index.ts create mode 100644 src/utils/form/rule.ts create mode 100644 src/views/system/login/components/BindWechat/index.vue create mode 100644 src/views/system/login/components/CodeLogin/index.vue create mode 100644 src/views/system/login/components/PwdLogin/components/OtherLogin.vue create mode 100644 src/views/system/login/components/PwdLogin/components/index.ts create mode 100644 src/views/system/login/components/PwdLogin/index.vue create mode 100644 src/views/system/login/components/Register/index.vue create mode 100644 src/views/system/login/components/ResetPwd/index.vue diff --git a/mock/api/auth.ts b/mock/api/auth.ts index 870a35b0..0efc995f 100644 --- a/mock/api/auth.ts +++ b/mock/api/auth.ts @@ -1,14 +1,61 @@ import type { MockMethod } from 'vite-plugin-mock'; +const token: ApiAuth.Token = { + token: '__TEMP_TOKEN__', + refreshToken: '__TEMP_REFRESH_TOKEN__' +}; + const apis: MockMethod[] = [ + // 获取验证码 { - url: '/mock/getUser', - method: 'get', - response: (): Service.BackendServiceResult => { + url: '/mock/getSmsCode', + method: 'post', + response: (): Service.BackendServiceResult => { return { code: 200, message: 'ok', - data: '测试mock数据' + data: true + }; + } + }, + // 密码登录 + { + url: '/mock/loginByPwd', + method: 'post', + response: (): Service.BackendServiceResult => { + return { + code: 200, + message: 'ok', + data: token + }; + } + }, + // 验证码登录 + { + url: '/mock/loginByCode', + method: 'post', + response: (): Service.BackendServiceResult => { + return { + code: 200, + message: 'ok', + data: token + }; + } + }, + // 获取用户信息(请求头携带token) + { + url: '/mock/getUserInfo', + method: 'get', + response: (): Service.BackendServiceResult => { + return { + code: 200, + message: 'ok', + data: { + userId: '0', + userName: 'Soybean', + userPhone: '15170283876', + userRole: 'super' + } }; } } diff --git a/mock/api/route.ts b/mock/api/route.ts index 4a332b86..66dec8a2 100644 --- a/mock/api/route.ts +++ b/mock/api/route.ts @@ -73,7 +73,7 @@ const routes: AuthRoute.Route[] = [ const routeHome: AuthRoute.RoutePath = '/dashboard/analysis'; -const data: ApiRoute.ResponseRoute = { +const data: ApiRoute.Route = { routes, home: routeHome }; diff --git a/package.json b/package.json index bf37383e..3d4dd80d 100644 --- a/package.json +++ b/package.json @@ -37,13 +37,13 @@ "devDependencies": { "@commitlint/cli": "^16.0.1", "@commitlint/config-conventional": "^16.0.0", - "@iconify/json": "^1.1.451", + "@iconify/json": "^1.1.452", "@iconify/vue": "^3.1.1", "@types/crypto-js": "^4.1.0", "@types/node": "^17.0.6", "@types/qs": "^6.9.7", "@typescript-eslint/eslint-plugin": "^5.8.1", - "@typescript-eslint/parser": "^5.8.1", + "@typescript-eslint/parser": "^5.9.0", "@vitejs/plugin-vue": "^2.0.1", "@vue/eslint-config-prettier": "^7.0.0", "@vue/eslint-config-typescript": "^10.0.0", @@ -54,11 +54,11 @@ "eslint": "^8.6.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-prettier": "^8.3.0", - "eslint-plugin-import": "^2.25.3", + "eslint-plugin-import": "^2.25.4", "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-vue": "^8.2.0", "husky": "^7.0.4", - "lint-staged": "^12.1.4", + "lint-staged": "^12.1.5", "mockjs": "^1.1.0", "patch-package": "^6.4.7", "postinstall-postinstall": "^2.1.0", @@ -72,7 +72,7 @@ "vite-plugin-html": "^2.1.2", "vite-plugin-mock": "^2.9.6", "vite-plugin-windicss": "^1.6.1", - "vue-tsc": "^0.30.1", + "vue-tsc": "^0.30.2", "vueuc": "^0.4.19", "windicss": "^3.4.2" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 86cdc563..13a7f0ab 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3,13 +3,13 @@ lockfileVersion: 5.3 specifiers: '@commitlint/cli': ^16.0.1 '@commitlint/config-conventional': ^16.0.0 - '@iconify/json': ^1.1.451 + '@iconify/json': ^1.1.452 '@iconify/vue': ^3.1.1 '@types/crypto-js': ^4.1.0 '@types/node': ^17.0.6 '@types/qs': ^6.9.7 '@typescript-eslint/eslint-plugin': ^5.8.1 - '@typescript-eslint/parser': ^5.8.1 + '@typescript-eslint/parser': ^5.9.0 '@vitejs/plugin-vue': ^2.0.1 '@vue/eslint-config-prettier': ^7.0.0 '@vue/eslint-config-typescript': ^10.0.0 @@ -25,12 +25,12 @@ specifiers: eslint: ^8.6.0 eslint-config-airbnb-base: ^15.0.0 eslint-config-prettier: ^8.3.0 - eslint-plugin-import: ^2.25.3 + eslint-plugin-import: ^2.25.4 eslint-plugin-prettier: ^4.0.0 eslint-plugin-vue: ^8.2.0 form-data: ^4.0.0 husky: ^7.0.4 - lint-staged: ^12.1.4 + lint-staged: ^12.1.5 lodash-es: ^4.17.21 mockjs: ^1.1.0 naive-ui: ^2.23.2 @@ -50,7 +50,7 @@ specifiers: vite-plugin-windicss: ^1.6.1 vue: ^3.2.26 vue-router: ^4.0.12 - vue-tsc: ^0.30.1 + vue-tsc: ^0.30.2 vueuc: ^0.4.19 windicss: ^3.4.2 @@ -71,13 +71,13 @@ dependencies: devDependencies: '@commitlint/cli': registry.npmmirror.com/@commitlint/cli/16.0.1_@types+node@17.0.6 '@commitlint/config-conventional': registry.npmmirror.com/@commitlint/config-conventional/16.0.0 - '@iconify/json': registry.npmmirror.com/@iconify/json/1.1.451 + '@iconify/json': registry.npmmirror.com/@iconify/json/1.1.452 '@iconify/vue': registry.npmmirror.com/@iconify/vue/3.1.1_vue@3.2.26 '@types/crypto-js': registry.npmmirror.com/@types/crypto-js/4.1.0 '@types/node': registry.npmmirror.com/@types/node/17.0.6 '@types/qs': registry.npmmirror.com/@types/qs/6.9.7 - '@typescript-eslint/eslint-plugin': registry.npmmirror.com/@typescript-eslint/eslint-plugin/5.8.1_13039593e64cd539d0b4c5c2da390958 - '@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser/5.8.1_eslint@8.6.0+typescript@4.5.4 + '@typescript-eslint/eslint-plugin': registry.npmmirror.com/@typescript-eslint/eslint-plugin/5.8.1_bd2fd93dbcc607ad2f21b784bccfe0c8 + '@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser/5.9.0_eslint@8.6.0+typescript@4.5.4 '@vitejs/plugin-vue': registry.npmmirror.com/@vitejs/plugin-vue/2.0.1_vite@2.7.10+vue@3.2.26 '@vue/eslint-config-prettier': registry.npmmirror.com/@vue/eslint-config-prettier/7.0.0_eslint@8.6.0+prettier@2.5.1 '@vue/eslint-config-typescript': registry.npmmirror.com/@vue/eslint-config-typescript/10.0.0_57f850728139557a3a27f1248f77f964 @@ -86,13 +86,13 @@ devDependencies: cz-conventional-changelog: registry.nlark.com/cz-conventional-changelog/3.3.0_@types+node@17.0.6 cz-customizable: registry.npmmirror.com/cz-customizable/6.3.0 eslint: registry.npmmirror.com/eslint/8.6.0 - eslint-config-airbnb-base: registry.npmmirror.com/eslint-config-airbnb-base/15.0.0_b54597effeb7d09a84a334cc3c3dadae + eslint-config-airbnb-base: registry.npmmirror.com/eslint-config-airbnb-base/15.0.0_b5a36b8c1535387c8dd00eff7ec6b551 eslint-config-prettier: registry.nlark.com/eslint-config-prettier/8.3.0_eslint@8.6.0 - eslint-plugin-import: registry.npmmirror.com/eslint-plugin-import/2.25.3_eslint@8.6.0 + eslint-plugin-import: registry.npmmirror.com/eslint-plugin-import/2.25.4_eslint@8.6.0 eslint-plugin-prettier: registry.npmmirror.com/eslint-plugin-prettier/4.0.0_1c588f61426b1faf18812943f1678311 eslint-plugin-vue: registry.npmmirror.com/eslint-plugin-vue/8.2.0_eslint@8.6.0 husky: registry.npmmirror.com/husky/7.0.4 - lint-staged: registry.npmmirror.com/lint-staged/12.1.4 + lint-staged: registry.npmmirror.com/lint-staged/12.1.5 mockjs: registry.npmmirror.com/mockjs/1.1.0 patch-package: registry.nlark.com/patch-package/6.4.7 postinstall-postinstall: registry.npmmirror.com/postinstall-postinstall/2.1.0 @@ -106,7 +106,7 @@ devDependencies: vite-plugin-html: registry.npmmirror.com/vite-plugin-html/2.1.2_vite@2.7.10 vite-plugin-mock: registry.npmmirror.com/vite-plugin-mock/2.9.6_mockjs@1.1.0+vite@2.7.10 vite-plugin-windicss: registry.npmmirror.com/vite-plugin-windicss/1.6.1_vite@2.7.10 - vue-tsc: registry.npmmirror.com/vue-tsc/0.30.1_typescript@4.5.4 + vue-tsc: registry.npmmirror.com/vue-tsc/0.30.2_typescript@4.5.4 vueuc: registry.npmmirror.com/vueuc/0.4.19_vue@3.2.26 windicss: registry.npmmirror.com/windicss/3.4.2 @@ -312,7 +312,7 @@ packages: engines: {node: '>= 8'} dependencies: normalize-path: registry.nlark.com/normalize-path/3.0.0 - picomatch: registry.nlark.com/picomatch/2.3.0 + picomatch: registry.npmmirror.com/picomatch/2.3.0 dev: true registry.nlark.com/argparse/2.0.1: @@ -919,7 +919,7 @@ packages: version: 0.3.6 dependencies: debug: registry.npmmirror.com/debug/3.2.7 - resolve: registry.nlark.com/resolve/1.20.0 + resolve: registry.npmmirror.com/resolve/1.20.0 dev: true registry.nlark.com/eslint-utils/3.0.0_eslint@8.6.0: @@ -1675,7 +1675,7 @@ packages: version: 1.0.0 dependencies: is-promise: registry.nlark.com/is-promise/2.2.2 - promise: registry.nlark.com/promise/7.3.1 + promise: registry.npmmirror.com/promise/7.3.1 dev: true registry.nlark.com/kind-of/6.0.3: @@ -1806,7 +1806,7 @@ packages: engines: {node: '>=8.6'} dependencies: braces: registry.nlark.com/braces/3.0.2 - picomatch: registry.nlark.com/picomatch/2.3.0 + picomatch: registry.npmmirror.com/picomatch/2.3.0 dev: true registry.nlark.com/mimic-fn/1.2.0: @@ -1888,7 +1888,7 @@ packages: version: 2.5.0 dependencies: hosted-git-info: registry.npmmirror.com/hosted-git-info/2.8.9 - resolve: registry.nlark.com/resolve/1.20.0 + resolve: registry.npmmirror.com/resolve/1.20.0 semver: registry.nlark.com/semver/5.7.1 validate-npm-package-license: registry.nlark.com/validate-npm-package-license/3.0.4 dev: true @@ -2186,14 +2186,6 @@ packages: fast-diff: registry.nlark.com/fast-diff/1.2.0 dev: true - registry.nlark.com/promise/7.3.1: - resolution: {integrity: sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=, registry: http://registry.npm.taobao.org/, tarball: https://registry.nlark.com/promise/download/promise-7.3.1.tgz} - name: promise - version: 7.3.1 - dependencies: - asap: registry.nlark.com/asap/2.0.6 - dev: true - registry.nlark.com/pug-attrs/3.0.0: resolution: {integrity: sha1-sQRR4DSBZeMfrRzCPr3dncc0fEE=, registry: http://registry.npm.taobao.org/, tarball: https://registry.nlark.com/pug-attrs/download/pug-attrs-3.0.0.tgz} name: pug-attrs @@ -2228,7 +2220,7 @@ packages: jstransformer: registry.nlark.com/jstransformer/1.0.0 pug-error: registry.npmmirror.com/pug-error/2.0.0 pug-walk: registry.nlark.com/pug-walk/2.0.0 - resolve: registry.nlark.com/resolve/1.20.0 + resolve: registry.npmmirror.com/resolve/1.20.0 dev: true registry.nlark.com/pug-lexer/5.0.1: @@ -2288,21 +2280,6 @@ packages: version: 2.0.0 dev: true - registry.nlark.com/pug/3.0.2: - resolution: {integrity: sha1-81xxBzQ0VOQ7wnrg/3bHMbeOpTU=, registry: http://registry.npm.taobao.org/, tarball: https://registry.nlark.com/pug/download/pug-3.0.2.tgz} - name: pug - version: 3.0.2 - dependencies: - pug-code-gen: registry.nlark.com/pug-code-gen/3.0.2 - pug-filters: registry.nlark.com/pug-filters/4.0.0 - pug-lexer: registry.nlark.com/pug-lexer/5.0.1 - pug-linker: registry.nlark.com/pug-linker/4.0.0 - pug-load: registry.nlark.com/pug-load/3.0.0 - pug-parser: registry.nlark.com/pug-parser/6.0.0 - pug-runtime: registry.nlark.com/pug-runtime/3.0.1 - pug-strip-comments: registry.nlark.com/pug-strip-comments/2.0.0 - dev: true - registry.nlark.com/punycode/2.1.1: resolution: {integrity: sha1-tYsBCsQMIsVldhbI0sLALHv0eew=, registry: http://registry.npm.taobao.org/, tarball: https://registry.nlark.com/punycode/download/punycode-2.1.1.tgz} name: punycode @@ -2352,7 +2329,7 @@ packages: version: 3.6.0 engines: {node: '>=8.10.0'} dependencies: - picomatch: registry.nlark.com/picomatch/2.3.0 + picomatch: registry.npmmirror.com/picomatch/2.3.0 dev: true registry.nlark.com/redent/3.0.0: @@ -3386,10 +3363,10 @@ packages: version: 1.2.1 dev: true - registry.npmmirror.com/@iconify/json/1.1.451: - resolution: {integrity: sha512-A+GgU4xetmBfofDQSBNENRsbZo3vMZTF4pkCxFObWs+y9j/C/oGwJwqiV3yrU9jFecF/MkffBbwNFug8j5EAtw==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@iconify/json/download/@iconify/json-1.1.451.tgz} + registry.npmmirror.com/@iconify/json/1.1.452: + resolution: {integrity: sha512-3eUNfCvfap5dE4JUePnul+3wCuWMSqD1zC9oGHqob5FRbJ05tGQ/n0FsL7WthqO5C+dLaMUMNRRG5VRwMzyYfA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@iconify/json/download/@iconify/json-1.1.452.tgz} name: '@iconify/json' - version: 1.1.451 + version: 1.1.452 dev: true registry.npmmirror.com/@iconify/types/1.0.12: @@ -3443,7 +3420,7 @@ packages: builtin-modules: registry.nlark.com/builtin-modules/3.2.0 deepmerge: registry.nlark.com/deepmerge/4.2.2 is-module: registry.npmmirror.com/is-module/1.0.0 - resolve: registry.nlark.com/resolve/1.20.0 + resolve: registry.npmmirror.com/resolve/1.20.0 dev: true registry.npmmirror.com/@rollup/pluginutils/3.1.0: @@ -3456,7 +3433,7 @@ packages: dependencies: '@types/estree': registry.npmmirror.com/@types/estree/0.0.39 estree-walker: registry.npmmirror.com/estree-walker/1.0.1 - picomatch: registry.nlark.com/picomatch/2.3.0 + picomatch: registry.npmmirror.com/picomatch/2.3.0 dev: true registry.npmmirror.com/@rollup/pluginutils/4.1.2: @@ -3594,7 +3571,7 @@ packages: dependencies: '@types/yargs-parser': registry.npmmirror.com/@types/yargs-parser/20.2.1 - registry.npmmirror.com/@typescript-eslint/eslint-plugin/5.8.1_13039593e64cd539d0b4c5c2da390958: + registry.npmmirror.com/@typescript-eslint/eslint-plugin/5.8.1_bd2fd93dbcc607ad2f21b784bccfe0c8: resolution: {integrity: sha512-wTZ5oEKrKj/8/366qTM366zqhIKAp6NCMweoRONtfuC07OAU9nVI2GZZdqQ1qD30WAAtcPdkH+npDwtRFdp4Rw==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/download/@typescript-eslint/eslint-plugin-5.8.1.tgz} id: registry.npmmirror.com/@typescript-eslint/eslint-plugin/5.8.1 name: '@typescript-eslint/eslint-plugin' @@ -3609,7 +3586,7 @@ packages: optional: true dependencies: '@typescript-eslint/experimental-utils': registry.npmmirror.com/@typescript-eslint/experimental-utils/5.8.1_eslint@8.6.0+typescript@4.5.4 - '@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser/5.8.1_eslint@8.6.0+typescript@4.5.4 + '@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser/5.9.0_eslint@8.6.0+typescript@4.5.4 '@typescript-eslint/scope-manager': registry.npmmirror.com/@typescript-eslint/scope-manager/5.8.1 debug: registry.npmmirror.com/debug/4.3.3 eslint: registry.npmmirror.com/eslint/8.6.0 @@ -3644,11 +3621,11 @@ packages: - typescript dev: true - registry.npmmirror.com/@typescript-eslint/parser/5.8.1_eslint@8.6.0+typescript@4.5.4: - resolution: {integrity: sha512-K1giKHAjHuyB421SoXMXFHHVI4NdNY603uKw92++D3qyxSeYvC10CBJ/GE5Thpo4WTUvu1mmJI2/FFkz38F2Gw==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/parser/download/@typescript-eslint/parser-5.8.1.tgz} - id: registry.npmmirror.com/@typescript-eslint/parser/5.8.1 + registry.npmmirror.com/@typescript-eslint/parser/5.9.0_eslint@8.6.0+typescript@4.5.4: + resolution: {integrity: sha512-/6pOPz8yAxEt4PLzgbFRDpZmHnXCeZgPDrh/1DaVKOjvn/UPMlWhbx/gA96xRi2JxY1kBl2AmwVbyROUqys5xQ==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/parser/download/@typescript-eslint/parser-5.9.0.tgz} + id: registry.npmmirror.com/@typescript-eslint/parser/5.9.0 name: '@typescript-eslint/parser' - version: 5.8.1 + version: 5.9.0 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -3657,9 +3634,9 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': registry.npmmirror.com/@typescript-eslint/scope-manager/5.8.1 - '@typescript-eslint/types': registry.npmmirror.com/@typescript-eslint/types/5.8.1 - '@typescript-eslint/typescript-estree': registry.npmmirror.com/@typescript-eslint/typescript-estree/5.8.1_typescript@4.5.4 + '@typescript-eslint/scope-manager': registry.npmmirror.com/@typescript-eslint/scope-manager/5.9.0 + '@typescript-eslint/types': registry.npmmirror.com/@typescript-eslint/types/5.9.0 + '@typescript-eslint/typescript-estree': registry.npmmirror.com/@typescript-eslint/typescript-estree/5.9.0_typescript@4.5.4 debug: registry.npmmirror.com/debug/4.3.3 eslint: registry.npmmirror.com/eslint/8.6.0 typescript: registry.npmmirror.com/typescript/4.5.4 @@ -3677,6 +3654,16 @@ packages: '@typescript-eslint/visitor-keys': registry.npmmirror.com/@typescript-eslint/visitor-keys/5.8.1 dev: true + registry.npmmirror.com/@typescript-eslint/scope-manager/5.9.0: + resolution: {integrity: sha512-DKtdIL49Qxk2a8icF6whRk7uThuVz4A6TCXfjdJSwOsf+9ree7vgQWcx0KOyCdk0i9ETX666p4aMhrRhxhUkyg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/scope-manager/download/@typescript-eslint/scope-manager-5.9.0.tgz} + name: '@typescript-eslint/scope-manager' + version: 5.9.0 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': registry.npmmirror.com/@typescript-eslint/types/5.9.0 + '@typescript-eslint/visitor-keys': registry.npmmirror.com/@typescript-eslint/visitor-keys/5.9.0 + dev: true + registry.npmmirror.com/@typescript-eslint/types/5.8.1: resolution: {integrity: sha512-L/FlWCCgnjKOLefdok90/pqInkomLnAcF9UAzNr+DSqMC3IffzumHTQTrINXhP1gVp9zlHiYYjvozVZDPleLcA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/types/download/@typescript-eslint/types-5.8.1.tgz} name: '@typescript-eslint/types' @@ -3684,6 +3671,13 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + registry.npmmirror.com/@typescript-eslint/types/5.9.0: + resolution: {integrity: sha512-mWp6/b56Umo1rwyGCk8fPIzb9Migo8YOniBGPAQDNC6C52SeyNGN4gsVwQTAR+RS2L5xyajON4hOLwAGwPtUwg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/types/download/@typescript-eslint/types-5.9.0.tgz} + name: '@typescript-eslint/types' + version: 5.9.0 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + registry.npmmirror.com/@typescript-eslint/typescript-estree/5.8.1_typescript@4.5.4: resolution: {integrity: sha512-26lQ8l8tTbG7ri7xEcCFT9ijU5Fk+sx/KRRyyzCv7MQ+rZZlqiDPtMKWLC8P7o+dtCnby4c+OlxuX1tp8WfafQ==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/typescript-estree/download/@typescript-eslint/typescript-estree-5.8.1.tgz} id: registry.npmmirror.com/@typescript-eslint/typescript-estree/5.8.1 @@ -3708,6 +3702,30 @@ packages: - supports-color dev: true + registry.npmmirror.com/@typescript-eslint/typescript-estree/5.9.0_typescript@4.5.4: + resolution: {integrity: sha512-kxo3xL2mB7XmiVZcECbaDwYCt3qFXz99tBSuVJR4L/sR7CJ+UNAPrYILILktGj1ppfZ/jNt/cWYbziJUlHl1Pw==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/typescript-estree/download/@typescript-eslint/typescript-estree-5.9.0.tgz} + id: registry.npmmirror.com/@typescript-eslint/typescript-estree/5.9.0 + name: '@typescript-eslint/typescript-estree' + version: 5.9.0 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': registry.npmmirror.com/@typescript-eslint/types/5.9.0 + '@typescript-eslint/visitor-keys': registry.npmmirror.com/@typescript-eslint/visitor-keys/5.9.0 + debug: registry.npmmirror.com/debug/4.3.3 + globby: registry.nlark.com/globby/11.0.4 + is-glob: registry.npmmirror.com/is-glob/4.0.3 + semver: registry.nlark.com/semver/7.3.5 + tsutils: registry.nlark.com/tsutils/3.21.0_typescript@4.5.4 + typescript: registry.npmmirror.com/typescript/4.5.4 + transitivePeerDependencies: + - supports-color + dev: true + registry.npmmirror.com/@typescript-eslint/visitor-keys/5.8.1: resolution: {integrity: sha512-SWgiWIwocK6NralrJarPZlWdr0hZnj5GXHIgfdm8hNkyKvpeQuFyLP6YjSIe9kf3YBIfU6OHSZLYkQ+smZwtNg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/visitor-keys/download/@typescript-eslint/visitor-keys-5.8.1.tgz} name: '@typescript-eslint/visitor-keys' @@ -3718,6 +3736,16 @@ packages: eslint-visitor-keys: registry.npmmirror.com/eslint-visitor-keys/3.1.0 dev: true + registry.npmmirror.com/@typescript-eslint/visitor-keys/5.9.0: + resolution: {integrity: sha512-6zq0mb7LV0ThExKlecvpfepiB+XEtFv/bzx7/jKSgyXTFD7qjmSu1FoiS0x3OZaiS+UIXpH2vd9O89f02RCtgw==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/visitor-keys/download/@typescript-eslint/visitor-keys-5.9.0.tgz} + name: '@typescript-eslint/visitor-keys' + version: 5.9.0 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': registry.npmmirror.com/@typescript-eslint/types/5.9.0 + eslint-visitor-keys: registry.npmmirror.com/eslint-visitor-keys/3.1.0 + dev: true + registry.npmmirror.com/@vitejs/plugin-vue/2.0.1_vite@2.7.10+vue@3.2.26: resolution: {integrity: sha512-wtdMnGVvys9K8tg+DxowU1ytTrdVveXr3LzdhaKakysgGXyrsfaeds2cDywtvujEASjWOwWL/OgWM+qoeM8Plg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vitejs/plugin-vue/download/@vitejs/plugin-vue-2.0.1.tgz} id: registry.npmmirror.com/@vitejs/plugin-vue/2.0.1 @@ -3732,61 +3760,62 @@ packages: vue: registry.npmmirror.com/vue/3.2.26 dev: true - registry.npmmirror.com/@volar/code-gen/0.30.1: - resolution: {integrity: sha512-qPT0ZGzLaaUArZ1b5qcso2GAFpgjxsPDRXnq0lgsSOpNO6lXJN5ZcWzFZXYPjMJSV1Rkm0ehK5tSUD+sD+pPWg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@volar/code-gen/download/@volar/code-gen-0.30.1.tgz} + registry.npmmirror.com/@volar/code-gen/0.30.2: + resolution: {integrity: sha512-75rlb3rw/O/HiXxrOsVJ8JhEssqtN4dJ0i6oG4kL0udr+QM0TwN0PqaEhoMRyMFV6kBPPSunBBJQ3XNAb0PtGA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@volar/code-gen/download/@volar/code-gen-0.30.2.tgz} name: '@volar/code-gen' - version: 0.30.1 + version: 0.30.2 dependencies: - '@volar/shared': registry.npmmirror.com/@volar/shared/0.30.1 - '@volar/source-map': registry.npmmirror.com/@volar/source-map/0.30.1 + '@volar/shared': registry.npmmirror.com/@volar/shared/0.30.2 + '@volar/source-map': registry.npmmirror.com/@volar/source-map/0.30.2 dev: true - registry.npmmirror.com/@volar/html2pug/0.30.1: - resolution: {integrity: sha512-ojJPrb4qSLrVNl9LTtdjZ5MFyeHmwJK4OVPTgFc/lyQ94nPS9JHba86SaTwDb2XEgiXBWQVEo12bRr3lW9H2+Q==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@volar/html2pug/download/@volar/html2pug-0.30.1.tgz} + registry.npmmirror.com/@volar/html2pug/0.30.2: + resolution: {integrity: sha512-k/DLGoXALaQgnacP1MoJ77AwnCHlKcsQKJJug8Qdou3+yOrzYjSSEP6uwG8BS0Fv1h4d4JYmlXsxW8gJPGXSQQ==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@volar/html2pug/download/@volar/html2pug-0.30.2.tgz} name: '@volar/html2pug' - version: 0.30.1 + version: 0.30.2 dependencies: domelementtype: registry.nlark.com/domelementtype/2.2.0 domhandler: registry.npmmirror.com/domhandler/4.3.0 htmlparser2: registry.npmmirror.com/htmlparser2/7.2.0 - pug: registry.nlark.com/pug/3.0.2 + pug: registry.npmmirror.com/pug/3.0.2 dev: true - registry.npmmirror.com/@volar/shared/0.30.1: - resolution: {integrity: sha512-6F5yQYeN+gbXAKplxHDvj4Ei+rHCjNhwkfZnGpaSpEU92uSI2vK/HfEdd/zTKdAZpwz0RjliNuFoXLi6umtQ0w==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@volar/shared/download/@volar/shared-0.30.1.tgz} + registry.npmmirror.com/@volar/shared/0.30.2: + resolution: {integrity: sha512-93Q7i758WjScg4ptvDcpk66r4Paz9StVMH/M5RCsU4/9F5a1xSCUJbkbpwE0zESkVzcuBatDqk79PaZ8TZKqRg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@volar/shared/download/@volar/shared-0.30.2.tgz} name: '@volar/shared' - version: 0.30.1 + version: 0.30.2 dependencies: upath: registry.nlark.com/upath/2.0.1 vscode-jsonrpc: registry.npmmirror.com/vscode-jsonrpc/8.0.0-next.4 vscode-uri: registry.npmmirror.com/vscode-uri/3.0.3 dev: true - registry.npmmirror.com/@volar/source-map/0.30.1: - resolution: {integrity: sha512-QGi36KBGHZ4gq81jPSi3W2wRcpso9Apd59AZOv/H98k5hU9zo8wA5hwartZHiybTlT1q/0Yno3agSj+vK2vocw==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@volar/source-map/download/@volar/source-map-0.30.1.tgz} + registry.npmmirror.com/@volar/source-map/0.30.2: + resolution: {integrity: sha512-gwa9OiSjUOZWYutJX53m/KDU/zaF0yN3RP2B8J0aMVyT5dE/VaIfknSxPAW5QFC6AT79Ea1HKGtChuSBgqHCfA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@volar/source-map/download/@volar/source-map-0.30.2.tgz} name: '@volar/source-map' - version: 0.30.1 + version: 0.30.2 dependencies: - '@volar/shared': registry.npmmirror.com/@volar/shared/0.30.1 + '@volar/shared': registry.npmmirror.com/@volar/shared/0.30.2 + vscode-languageserver-textdocument: registry.npmmirror.com/vscode-languageserver-textdocument/1.0.3 dev: true - registry.npmmirror.com/@volar/transforms/0.30.1: - resolution: {integrity: sha512-dWFyfQGLoZ8LZI93zud0c5uoCdlkwDBi90G/XaaKfXxkX+3eiJrM0lJ/d1Nc0L04t9mb28I5hpVK68vH90+Tlw==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@volar/transforms/download/@volar/transforms-0.30.1.tgz} + registry.npmmirror.com/@volar/transforms/0.30.2: + resolution: {integrity: sha512-bc+55NGlBbMLHkpChqAEgsblYJxjNHiKVMbVUMi52xKa2l9gOWXNbn5WRsHfz4AR+Cq/Zm0AvVJ10ehLQsGsow==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@volar/transforms/download/@volar/transforms-0.30.2.tgz} name: '@volar/transforms' - version: 0.30.1 + version: 0.30.2 dependencies: - '@volar/shared': registry.npmmirror.com/@volar/shared/0.30.1 - vscode-languageserver: registry.npmmirror.com/vscode-languageserver/8.0.0-next.5 + '@volar/shared': registry.npmmirror.com/@volar/shared/0.30.2 + vscode-languageserver-types: registry.npmmirror.com/vscode-languageserver-types/3.17.0-next.5 dev: true - registry.npmmirror.com/@volar/vue-code-gen/0.30.1: - resolution: {integrity: sha512-+0egr84YOYLudP6jRXRm+xtAL92GTPaq0U0lsorLTBp/MB14Fap6HMUr/LEeNB5tnND36UQJiUWHM5eTDAAb4Q==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@volar/vue-code-gen/download/@volar/vue-code-gen-0.30.1.tgz} + registry.npmmirror.com/@volar/vue-code-gen/0.30.2: + resolution: {integrity: sha512-kJyVkQFhMvVQ32aDaC6h5DdXG1GJbJjeeAkCnjfCJfMmuYjM5R4QNZHDz1TI0dETgF9vP+kbAukQKNWecHK3qg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@volar/vue-code-gen/download/@volar/vue-code-gen-0.30.2.tgz} name: '@volar/vue-code-gen' - version: 0.30.1 + version: 0.30.2 dependencies: - '@volar/code-gen': registry.npmmirror.com/@volar/code-gen/0.30.1 - '@volar/shared': registry.npmmirror.com/@volar/shared/0.30.1 - '@volar/source-map': registry.npmmirror.com/@volar/source-map/0.30.1 + '@volar/code-gen': registry.npmmirror.com/@volar/code-gen/0.30.2 + '@volar/shared': registry.npmmirror.com/@volar/shared/0.30.2 + '@volar/source-map': registry.npmmirror.com/@volar/source-map/0.30.2 '@vue/compiler-core': registry.npmmirror.com/@vue/compiler-core/3.2.26 '@vue/compiler-dom': registry.npmmirror.com/@vue/compiler-dom/3.2.26 '@vue/shared': registry.npmmirror.com/@vue/shared/3.2.26 @@ -3881,8 +3910,8 @@ packages: eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 eslint-plugin-vue: ^8.0.1 dependencies: - '@typescript-eslint/eslint-plugin': registry.npmmirror.com/@typescript-eslint/eslint-plugin/5.8.1_13039593e64cd539d0b4c5c2da390958 - '@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser/5.8.1_eslint@8.6.0+typescript@4.5.4 + '@typescript-eslint/eslint-plugin': registry.npmmirror.com/@typescript-eslint/eslint-plugin/5.8.1_bd2fd93dbcc607ad2f21b784bccfe0c8 + '@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser/5.9.0_eslint@8.6.0+typescript@4.5.4 eslint: registry.npmmirror.com/eslint/8.6.0 eslint-plugin-vue: registry.npmmirror.com/eslint-plugin-vue/8.2.0_eslint@8.6.0 vue-eslint-parser: registry.npmmirror.com/vue-eslint-parser/8.0.1_eslint@8.6.0 @@ -4766,7 +4795,7 @@ packages: esbuild-windows-arm64: registry.npmmirror.com/esbuild-windows-arm64/0.13.15 dev: true - registry.npmmirror.com/eslint-config-airbnb-base/15.0.0_b54597effeb7d09a84a334cc3c3dadae: + registry.npmmirror.com/eslint-config-airbnb-base/15.0.0_b5a36b8c1535387c8dd00eff7ec6b551: resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-config-airbnb-base/download/eslint-config-airbnb-base-15.0.0.tgz} id: registry.npmmirror.com/eslint-config-airbnb-base/15.0.0 name: eslint-config-airbnb-base @@ -4778,28 +4807,27 @@ packages: dependencies: confusing-browser-globals: registry.npmmirror.com/confusing-browser-globals/1.0.11 eslint: registry.npmmirror.com/eslint/8.6.0 - eslint-plugin-import: registry.npmmirror.com/eslint-plugin-import/2.25.3_eslint@8.6.0 + eslint-plugin-import: registry.npmmirror.com/eslint-plugin-import/2.25.4_eslint@8.6.0 object.assign: registry.nlark.com/object.assign/4.1.2 object.entries: registry.npmmirror.com/object.entries/1.1.5 semver: registry.nlark.com/semver/6.3.0 dev: true - registry.npmmirror.com/eslint-module-utils/2.7.1: - resolution: {integrity: sha1-tDUAHJ+N1Kt/bQ78rkuWltTCS3w=, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-module-utils/download/eslint-module-utils-2.7.1.tgz} + registry.npmmirror.com/eslint-module-utils/2.7.2: + resolution: {integrity: sha512-zquepFnWCY2ISMFwD/DqzaM++H+7PDzOpUvotJWm/y1BAFt5R4oeULgdrTejKqLkz7MA/tgstsUMNYc7wNdTrg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-module-utils/download/eslint-module-utils-2.7.2.tgz} name: eslint-module-utils - version: 2.7.1 + version: 2.7.2 engines: {node: '>=4'} dependencies: debug: registry.npmmirror.com/debug/3.2.7 find-up: registry.npmmirror.com/find-up/2.1.0 - pkg-dir: registry.npmmirror.com/pkg-dir/2.0.0 dev: true - registry.npmmirror.com/eslint-plugin-import/2.25.3_eslint@8.6.0: - resolution: {integrity: sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-plugin-import/download/eslint-plugin-import-2.25.3.tgz} - id: registry.npmmirror.com/eslint-plugin-import/2.25.3 + registry.npmmirror.com/eslint-plugin-import/2.25.4_eslint@8.6.0: + resolution: {integrity: sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-plugin-import/download/eslint-plugin-import-2.25.4.tgz} + id: registry.npmmirror.com/eslint-plugin-import/2.25.4 name: eslint-plugin-import - version: 2.25.3 + version: 2.25.4 engines: {node: '>=4'} peerDependencies: eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 @@ -4810,13 +4838,13 @@ packages: doctrine: registry.nlark.com/doctrine/2.1.0 eslint: registry.npmmirror.com/eslint/8.6.0 eslint-import-resolver-node: registry.nlark.com/eslint-import-resolver-node/0.3.6 - eslint-module-utils: registry.npmmirror.com/eslint-module-utils/2.7.1 + eslint-module-utils: registry.npmmirror.com/eslint-module-utils/2.7.2 has: registry.nlark.com/has/1.0.3 is-core-module: registry.npmmirror.com/is-core-module/2.8.0 is-glob: registry.npmmirror.com/is-glob/4.0.3 minimatch: registry.nlark.com/minimatch/3.0.4 object.values: registry.npmmirror.com/object.values/1.1.5 - resolve: registry.nlark.com/resolve/1.20.0 + resolve: registry.npmmirror.com/resolve/1.20.0 tsconfig-paths: registry.npmmirror.com/tsconfig-paths/3.12.0 dev: true @@ -5192,7 +5220,7 @@ packages: dev: true registry.npmmirror.com/htmlparser2/7.2.0: - resolution: {integrity: sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/htmlparser2/download/htmlparser2-7.2.0.tgz?cache=0&sync_timestamp=1636641904600&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fhtmlparser2%2Fdownload%2Fhtmlparser2-7.2.0.tgz} + resolution: {integrity: sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/htmlparser2/download/htmlparser2-7.2.0.tgz?cache=0&sync_timestamp=1636641716463&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fhtmlparser2%2Fdownload%2Fhtmlparser2-7.2.0.tgz} name: htmlparser2 version: 7.2.0 dependencies: @@ -5380,10 +5408,10 @@ packages: version: 1.2.4 dev: true - registry.npmmirror.com/lint-staged/12.1.4: - resolution: {integrity: sha512-RgDz9nsFsE0/5eL9Vat0AvCuk0+j5mEuzBIVfrRH5FRtt5wibYe8zTjZs2nuqLFrLAGQGYnj8+HJxolcj08i/A==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lint-staged/download/lint-staged-12.1.4.tgz} + registry.npmmirror.com/lint-staged/12.1.5: + resolution: {integrity: sha512-WyKb+0sNKDTd1LwwAfTBPp0XmdaKkAOEbg4oHE4Kq2+oQVchg/VAcjVQtSqZih1izNsTURjc2EkhG/syRQUXdA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lint-staged/download/lint-staged-12.1.5.tgz} name: lint-staged - version: 12.1.4 + version: 12.1.5 engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} hasBin: true dependencies: @@ -5599,7 +5627,7 @@ packages: version: 4.0.1 engines: {node: '>=8'} dependencies: - path-key: registry.nlark.com/path-key/3.1.1 + path-key: registry.npmmirror.com/path-key/3.1.1 dev: true registry.npmmirror.com/object-inspect/1.12.0: @@ -5683,11 +5711,25 @@ packages: lines-and-columns: registry.npmmirror.com/lines-and-columns/1.2.4 dev: true + registry.npmmirror.com/path-key/3.1.1: + resolution: {integrity: sha1-WB9q3mWMu6ZaDTOA3ndTKVBU83U=, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/path-key/download/path-key-3.1.1.tgz} + name: path-key + version: 3.1.1 + engines: {node: '>=8'} + dev: true + registry.npmmirror.com/picocolors/1.0.0: resolution: {integrity: sha1-y1vcdP8/UYkiNur3nWi8RFZKuBw=, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/picocolors/download/picocolors-1.0.0.tgz} name: picocolors version: 1.0.0 + registry.npmmirror.com/picomatch/2.3.0: + resolution: {integrity: sha1-8fBh3o9qS/AiiS4tEoI0+5gwKXI=, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/picomatch/download/picomatch-2.3.0.tgz} + name: picomatch + version: 2.3.0 + engines: {node: '>=8.6'} + dev: true + registry.npmmirror.com/pinia/2.0.9_typescript@4.5.4+vue@3.2.26: resolution: {integrity: sha512-iuYdxLJKQ07YPyOHYH05wNG9eKWqkP/4y4GE8+RqEYtz5fwHgPA5kr6zQbg/DoEJGnR2XCm1w1vdt6ppzL9ATg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/pinia/download/pinia-2.0.9.tgz} id: registry.npmmirror.com/pinia/2.0.9 @@ -5709,15 +5751,6 @@ packages: vue-demi: registry.npmmirror.com/vue-demi/0.12.1_vue@3.2.26 dev: false - registry.npmmirror.com/pkg-dir/2.0.0: - resolution: {integrity: sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/pkg-dir/download/pkg-dir-2.0.0.tgz} - name: pkg-dir - version: 2.0.0 - engines: {node: '>=4'} - dependencies: - find-up: registry.npmmirror.com/find-up/2.1.0 - dev: true - registry.npmmirror.com/postcss/8.4.5: resolution: {integrity: sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/postcss/download/postcss-8.4.5.tgz} name: postcss @@ -5761,12 +5794,35 @@ packages: engines: {node: '>=0.4.0'} dev: true + registry.npmmirror.com/promise/7.3.1: + resolution: {integrity: sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/promise/download/promise-7.3.1.tgz} + name: promise + version: 7.3.1 + dependencies: + asap: registry.nlark.com/asap/2.0.6 + dev: true + registry.npmmirror.com/pug-error/2.0.0: resolution: {integrity: sha1-XGIXPLCcNN4qLOBPF7it/sdNjKU=, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/pug-error/download/pug-error-2.0.0.tgz} name: pug-error version: 2.0.0 dev: true + registry.npmmirror.com/pug/3.0.2: + resolution: {integrity: sha1-81xxBzQ0VOQ7wnrg/3bHMbeOpTU=, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/pug/download/pug-3.0.2.tgz} + name: pug + version: 3.0.2 + dependencies: + pug-code-gen: registry.nlark.com/pug-code-gen/3.0.2 + pug-filters: registry.nlark.com/pug-filters/4.0.0 + pug-lexer: registry.nlark.com/pug-lexer/5.0.1 + pug-linker: registry.nlark.com/pug-linker/4.0.0 + pug-load: registry.nlark.com/pug-load/3.0.0 + pug-parser: registry.nlark.com/pug-parser/6.0.0 + pug-runtime: registry.nlark.com/pug-runtime/3.0.1 + pug-strip-comments: registry.nlark.com/pug-strip-comments/2.0.0 + dev: true + registry.npmmirror.com/qs/6.10.2: resolution: {integrity: sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/qs/download/qs-6.10.2.tgz} name: qs @@ -5805,6 +5861,15 @@ packages: version: 0.5.6 dev: true + registry.npmmirror.com/resolve/1.20.0: + resolution: {integrity: sha1-YpoBP7P3B1XW8LeTXMHCxTeLGXU=, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/resolve/download/resolve-1.20.0.tgz} + name: resolve + version: 1.20.0 + dependencies: + is-core-module: registry.npmmirror.com/is-core-module/2.8.0 + path-parse: registry.nlark.com/path-parse/1.0.7 + dev: true + registry.npmmirror.com/reusify/1.0.4: resolution: {integrity: sha1-kNo4Kx4SbvwCFG6QhFqI2xKSXXY=, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/reusify/download/reusify-1.0.4.tgz} name: reusify @@ -6421,30 +6486,32 @@ packages: version: 5.0.0 dev: true - registry.npmmirror.com/vscode-pug-languageservice/0.30.1: - resolution: {integrity: sha512-ytco+lziRQNrpHpI8X+/rhYaX4KUWAnYZHd1f1epu2m+9WoIf9swbk8/slIOeyec1DPg4Y7AS8hTLcEfOfY71g==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vscode-pug-languageservice/download/vscode-pug-languageservice-0.30.1.tgz} + registry.npmmirror.com/vscode-pug-languageservice/0.30.2: + resolution: {integrity: sha512-YkrBodqSzNrtLaEIeMnRJAcnqCWysIiOdkzxF6XHuOc+wDvbZ1U4XgxoLvNNjQdzNQIEYKbsLW0ldq5TYphjiA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vscode-pug-languageservice/download/vscode-pug-languageservice-0.30.2.tgz} name: vscode-pug-languageservice - version: 0.30.1 + version: 0.30.2 dependencies: - '@volar/code-gen': registry.npmmirror.com/@volar/code-gen/0.30.1 - '@volar/shared': registry.npmmirror.com/@volar/shared/0.30.1 - '@volar/source-map': registry.npmmirror.com/@volar/source-map/0.30.1 - '@volar/transforms': registry.npmmirror.com/@volar/transforms/0.30.1 + '@volar/code-gen': registry.npmmirror.com/@volar/code-gen/0.30.2 + '@volar/shared': registry.npmmirror.com/@volar/shared/0.30.2 + '@volar/source-map': registry.npmmirror.com/@volar/source-map/0.30.2 + '@volar/transforms': registry.npmmirror.com/@volar/transforms/0.30.2 pug-lexer: registry.nlark.com/pug-lexer/5.0.1 pug-parser: registry.nlark.com/pug-parser/6.0.0 - vscode-languageserver: registry.npmmirror.com/vscode-languageserver/8.0.0-next.5 + vscode-languageserver-textdocument: registry.npmmirror.com/vscode-languageserver-textdocument/1.0.3 + vscode-languageserver-types: registry.npmmirror.com/vscode-languageserver-types/3.17.0-next.5 dev: true - registry.npmmirror.com/vscode-typescript-languageservice/0.30.1: - resolution: {integrity: sha512-7EBJiaLXThlrbm2K5VU+qWPR3z+RtmCFLWiZaNdJYO/E5UFBQiPmO8qXlxcB2x1N7zId2GZoogAbT15oexY2eQ==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vscode-typescript-languageservice/download/vscode-typescript-languageservice-0.30.1.tgz} + registry.npmmirror.com/vscode-typescript-languageservice/0.30.2: + resolution: {integrity: sha512-5l+gMfbHTZnJy7V7xdH78ai1ViR/scrIVQT5KFraDWLKTYHjGBkHDZ1E9fF+jbeyEizyy2ayldTQ7kCz8jWqVA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vscode-typescript-languageservice/download/vscode-typescript-languageservice-0.30.2.tgz} name: vscode-typescript-languageservice - version: 0.30.1 + version: 0.30.2 dependencies: - '@volar/shared': registry.npmmirror.com/@volar/shared/0.30.1 + '@volar/shared': registry.npmmirror.com/@volar/shared/0.30.2 semver: registry.nlark.com/semver/7.3.5 upath: registry.nlark.com/upath/2.0.1 - vscode-languageserver: registry.npmmirror.com/vscode-languageserver/8.0.0-next.5 + vscode-languageserver-protocol: registry.npmmirror.com/vscode-languageserver-protocol/3.17.0-next.11 vscode-languageserver-textdocument: registry.npmmirror.com/vscode-languageserver-textdocument/1.0.3 + vscode-nls: registry.npmmirror.com/vscode-nls/5.0.0 dev: true registry.npmmirror.com/vscode-uri/2.1.2: @@ -6459,17 +6526,17 @@ packages: version: 3.0.3 dev: true - registry.npmmirror.com/vscode-vue-languageservice/0.30.1: - resolution: {integrity: sha512-l9R5vXkrGY0N4hA2o9ZFBIKL44z7UbHc45YjOmnslGwYL15YXfb7T4quW8VYSWJNRbiFBTNnNLWORIDEcWazBA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vscode-vue-languageservice/download/vscode-vue-languageservice-0.30.1.tgz} + registry.npmmirror.com/vscode-vue-languageservice/0.30.2: + resolution: {integrity: sha512-P0g92JmnVkV2zrWhDbT2zxuOUp0X2kMM9VHlrT7ALZq8wAhPOW0B4nhhb9a6jKBh6qqFBDquNeQRvTEZp4NJMA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vscode-vue-languageservice/download/vscode-vue-languageservice-0.30.2.tgz} name: vscode-vue-languageservice - version: 0.30.1 + version: 0.30.2 dependencies: - '@volar/code-gen': registry.npmmirror.com/@volar/code-gen/0.30.1 - '@volar/html2pug': registry.npmmirror.com/@volar/html2pug/0.30.1 - '@volar/shared': registry.npmmirror.com/@volar/shared/0.30.1 - '@volar/source-map': registry.npmmirror.com/@volar/source-map/0.30.1 - '@volar/transforms': registry.npmmirror.com/@volar/transforms/0.30.1 - '@volar/vue-code-gen': registry.npmmirror.com/@volar/vue-code-gen/0.30.1 + '@volar/code-gen': registry.npmmirror.com/@volar/code-gen/0.30.2 + '@volar/html2pug': registry.npmmirror.com/@volar/html2pug/0.30.2 + '@volar/shared': registry.npmmirror.com/@volar/shared/0.30.2 + '@volar/source-map': registry.npmmirror.com/@volar/source-map/0.30.2 + '@volar/transforms': registry.npmmirror.com/@volar/transforms/0.30.2 + '@volar/vue-code-gen': registry.npmmirror.com/@volar/vue-code-gen/0.30.2 '@vscode/emmet-helper': registry.npmmirror.com/@vscode/emmet-helper/2.8.3 '@vue/reactivity': registry.npmmirror.com/@vue/reactivity/3.2.26 '@vue/shared': registry.npmmirror.com/@vue/shared/3.2.26 @@ -6479,9 +6546,10 @@ packages: vscode-html-languageservice: registry.npmmirror.com/vscode-html-languageservice/4.2.1 vscode-json-languageservice: registry.npmmirror.com/vscode-json-languageservice/4.1.10 vscode-languageserver: registry.npmmirror.com/vscode-languageserver/8.0.0-next.5 + vscode-languageserver-protocol: registry.npmmirror.com/vscode-languageserver-protocol/3.17.0-next.11 vscode-languageserver-textdocument: registry.npmmirror.com/vscode-languageserver-textdocument/1.0.3 - vscode-pug-languageservice: registry.npmmirror.com/vscode-pug-languageservice/0.30.1 - vscode-typescript-languageservice: registry.npmmirror.com/vscode-typescript-languageservice/0.30.1 + vscode-pug-languageservice: registry.npmmirror.com/vscode-pug-languageservice/0.30.2 + vscode-typescript-languageservice: registry.npmmirror.com/vscode-typescript-languageservice/0.30.2 dev: true registry.npmmirror.com/vue-demi/0.12.1_vue@3.2.26: @@ -6535,18 +6603,18 @@ packages: vue: registry.npmmirror.com/vue/3.2.26 dev: false - registry.npmmirror.com/vue-tsc/0.30.1_typescript@4.5.4: - resolution: {integrity: sha512-AVBPWF70LvuzAt6phaF3U8pg1WmjmZQBfZvkX4Ve9EHTPh4R2JiJnSjf3MQgnx03qF5w0PGkBJ90l12aaLZeKQ==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vue-tsc/download/vue-tsc-0.30.1.tgz} - id: registry.npmmirror.com/vue-tsc/0.30.1 + registry.npmmirror.com/vue-tsc/0.30.2_typescript@4.5.4: + resolution: {integrity: sha512-A8KIk5KwQTbSdsrDxwJkFYLPqDJ1zM86w3X8cgpi6rveozKUGDMPt300awEz61sTuBM9fAfUhNRcsWbsJ1I+TQ==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vue-tsc/download/vue-tsc-0.30.2.tgz} + id: registry.npmmirror.com/vue-tsc/0.30.2 name: vue-tsc - version: 0.30.1 + version: 0.30.2 hasBin: true peerDependencies: typescript: '*' dependencies: - '@volar/shared': registry.npmmirror.com/@volar/shared/0.30.1 + '@volar/shared': registry.npmmirror.com/@volar/shared/0.30.2 typescript: registry.npmmirror.com/typescript/4.5.4 - vscode-vue-languageservice: registry.npmmirror.com/vscode-vue-languageservice/0.30.1 + vscode-vue-languageservice: registry.npmmirror.com/vscode-vue-languageservice/0.30.2 dev: true registry.npmmirror.com/vue/3.2.26: diff --git a/src/AppProvider.vue b/src/AppProvider.vue index 83287638..c62407e1 100644 --- a/src/AppProvider.vue +++ b/src/AppProvider.vue @@ -1,5 +1,5 @@ diff --git a/src/components/business/LoginAgreement/index.vue b/src/components/business/LoginAgreement/index.vue new file mode 100644 index 00000000..35c08601 --- /dev/null +++ b/src/components/business/LoginAgreement/index.vue @@ -0,0 +1,48 @@ + + + + diff --git a/src/components/business/index.ts b/src/components/business/index.ts new file mode 100644 index 00000000..19a8aa1b --- /dev/null +++ b/src/components/business/index.ts @@ -0,0 +1,3 @@ +import LoginAgreement from './LoginAgreement/index.vue'; + +export { LoginAgreement }; diff --git a/src/components/common/DarkModeSwitch/index.vue b/src/components/common/DarkModeSwitch/index.vue new file mode 100644 index 00000000..823524fa --- /dev/null +++ b/src/components/common/DarkModeSwitch/index.vue @@ -0,0 +1,39 @@ + + + + diff --git a/src/components/common/index.ts b/src/components/common/index.ts index a2152a29..172c886d 100644 --- a/src/components/common/index.ts +++ b/src/components/common/index.ts @@ -1,3 +1,4 @@ import SystemLogo from './SystemLogo/index.vue'; +import DarkModeSwitch from './DarkModeSwitch/index.vue'; -export { SystemLogo }; +export { SystemLogo, DarkModeSwitch }; diff --git a/src/components/custom/ImageVerify/index.vue b/src/components/custom/ImageVerify/index.vue new file mode 100644 index 00000000..12dfbc49 --- /dev/null +++ b/src/components/custom/ImageVerify/index.vue @@ -0,0 +1,39 @@ + + + + diff --git a/src/components/custom/index.ts b/src/components/custom/index.ts new file mode 100644 index 00000000..163e759d --- /dev/null +++ b/src/components/custom/index.ts @@ -0,0 +1,3 @@ +import ImageVerify from './ImageVerify/index.vue'; + +export { ImageVerify }; diff --git a/src/components/index.ts b/src/components/index.ts index d0b93236..2047bf38 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1 +1,3 @@ export * from './common'; +export * from './custom'; +export * from './business'; diff --git a/src/composables/common/index.ts b/src/composables/common/index.ts index 4b58cda6..7c20b36c 100644 --- a/src/composables/common/index.ts +++ b/src/composables/common/index.ts @@ -1 +1,3 @@ export * from './system'; +export * from './router'; +export * from './route'; diff --git a/src/composables/common/route.ts b/src/composables/common/route.ts new file mode 100644 index 00000000..860e9f36 --- /dev/null +++ b/src/composables/common/route.ts @@ -0,0 +1,32 @@ +import { unref, computed } from 'vue'; +import { useRoute } from 'vue-router'; +import { router } from '@/router'; +import { useRouteStore } from '@/store'; + +/** + * 路由查询参数 + * @param inSetup - 是否在vue页面/组件的setup里面调用,在axios里面无法使用useRouter和useRoute + */ +export function useRouteQuery(inSetup: boolean = true) { + const { getRouteName } = useRouteStore(); + + const route = getRouteInstance(inSetup); + + /** 登录后跳转的地址 */ + const loginRedirect = computed(() => { + let url: string | undefined; + if (route.name === getRouteName('login')) { + url = (route.query?.redirect as string) || ''; + } + return url; + }); + + return { + loginRedirect + }; +} + +function getRouteInstance(inSetup: boolean = true) { + const route = inSetup ? useRoute() : unref(router.currentRoute); + return route; +} diff --git a/src/composables/common/router.ts b/src/composables/common/router.ts new file mode 100644 index 00000000..09b8d4d3 --- /dev/null +++ b/src/composables/common/router.ts @@ -0,0 +1,90 @@ +import { unref } from 'vue'; +import { useRouter, useRoute } from 'vue-router'; +import type { RouteLocationRaw } from 'vue-router'; +import { router as globalRouter } from '@/router'; +import { useRouteStore } from '@/store'; +import { LoginModuleKey } from '@/interface'; + +/** + * 路由跳转 + * @param inSetup - 是否在vue页面/组件的setup里面调用,在axios里面无法使用useRouter和useRoute + */ +export function useRouterPush(inSetup: boolean = true) { + const { getRouteName } = useRouteStore(); + + const router = inSetup ? useRouter() : globalRouter; + const route = inSetup ? useRoute() : unref(globalRouter.currentRoute); + + /** + * 路由跳转 + * @param to - 需要跳转的路由 + * @param newTab - 是否在新的浏览器Tab标签打开 + */ + function routerPush(to: RouteLocationRaw, newTab = false) { + if (newTab) { + const routerData = router.resolve(to); + window.open(routerData.href, '_blank'); + } else { + router.push(to); + } + } + + /** 返回上一级路由 */ + function routerBack() { + router.go(-1); + } + + /** + * 跳转首页 + * @param newTab - 在新的浏览器标签打开 + */ + function toHome(newTab = false) { + routerPush(getRouteName('root'), newTab); + } + + /** + * 跳转登录页面 + * @param loginModule - 展示的登录模块 + * @param redirectUrl - 重定向地址(登录成功后跳转的地址),默认undefined表示取当前地址为重定向地址 + */ + function toLogin(loginModule?: LoginModuleKey, redirectUrl?: string) { + const module: LoginModuleKey = loginModule || 'pwd-login'; + const routeLocation: RouteLocationRaw = { + name: getRouteName('login'), + params: { module } + }; + const redirect = redirectUrl || route.fullPath; + Object.assign(routeLocation, { query: { redirect } }); + routerPush(routeLocation); + } + + /** + * 登录页切换其他模块 + * @param module - 切换后的登录模块 + */ + function toLoginModule(module: LoginModuleKey) { + const { query } = route; + routerPush({ name: getRouteName('login'), params: { module }, query }); + } + + /** + * 登录成功后跳转重定向的地址 + * @param redirect - 重定向地址 + */ + function toLoginRedirect(redirect?: string) { + if (redirect) { + routerPush(redirect); + } else { + toHome(); + } + } + + return { + routerPush, + routerBack, + toHome, + toLogin, + toLoginModule, + toLoginRedirect + }; +} diff --git a/src/config/common/index.ts b/src/config/common/index.ts index f78beabc..429cade5 100644 --- a/src/config/common/index.ts +++ b/src/config/common/index.ts @@ -1 +1,2 @@ export * from './service'; +export * from './regexp'; diff --git a/src/config/common/regexp.ts b/src/config/common/regexp.ts new file mode 100644 index 00000000..847a5eb9 --- /dev/null +++ b/src/config/common/regexp.ts @@ -0,0 +1,16 @@ +/** 手机号码正则 */ +export const REGEXP_PHONE = + /^[1](([3][0-9])|([4][0,1,4-9])|([5][0-3,5-9])|([6][2,5,6,7])|([7][0-8])|([8][0-9])|([9][0-3,5-9]))[0-9]{8}$/; + +/** 邮箱正则 */ +export const REGEXP_EMAIL = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/; + +/** 密码正则(密码为8-18位数字/字符/符号的组合) */ +export const REGEXP_PWD = + /^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)]|[()])+$)(?!^.*[\u4E00-\u9FA5].*$)([^(0-9a-zA-Z)]|[()]|[a-z]|[A-Z]|[0-9]){8,18}$/; + +/** 6位数字验证码正则 */ +export const REGEXP_CODE_SIX = /^\d{6}$/; + +/** 4位数字验证码正则 */ +export const REGEXP_CODE_FOUR = /^\d{4}$/; diff --git a/src/hooks/business/index.ts b/src/hooks/business/index.ts new file mode 100644 index 00000000..cbc26398 --- /dev/null +++ b/src/hooks/business/index.ts @@ -0,0 +1,5 @@ +import useCountDown from './useCountDown'; +import useSmsCode from './useSmsCode'; +import useImageVerify from './useImageVerify'; + +export { useCountDown, useSmsCode, useImageVerify }; diff --git a/src/hooks/business/useCountDown.ts b/src/hooks/business/useCountDown.ts new file mode 100644 index 00000000..d3951ba8 --- /dev/null +++ b/src/hooks/business/useCountDown.ts @@ -0,0 +1,52 @@ +import { ref, computed } from 'vue'; +import { useBoolean } from '../common'; + +/** + * 倒计时 + * @param second - 倒计时的时间(s) + */ +export default function useCountDown(second: number) { + if (second <= 0 && second % 1 !== 0) { + throw Error('倒计时的时间应该为一个正整数!'); + } + const { bool: isComplete, setTrue, setFalse } = useBoolean(false); + + const counts = ref(0); + const isCounting = computed(() => Boolean(counts.value)); + + let intervalId: any; + + /** + * 开始计时 + * @param updateSecond - 更改初时传入的倒计时时间 + */ + function start(updateSecond: number = second) { + if (!counts.value) { + setFalse(); + counts.value = updateSecond; + intervalId = setInterval(() => { + counts.value -= 1; + if (counts.value <= 0) { + clearInterval(intervalId); + setTrue(); + } + }, 1000); + } + } + + /** + * 停止计时 + */ + function stop() { + intervalId = clearInterval(intervalId); + counts.value = 0; + } + + return { + counts, + isCounting, + start, + stop, + isComplete + }; +} diff --git a/src/hooks/business/useImageVerify.ts b/src/hooks/business/useImageVerify.ts new file mode 100644 index 00000000..3978ead5 --- /dev/null +++ b/src/hooks/business/useImageVerify.ts @@ -0,0 +1,85 @@ +import { ref, onMounted } from 'vue'; + +/** + * 绘制图形验证码 + * @param width - 图形宽度 + * @param height - 图形高度 + */ +export default function useImageVerify(width = 152, height = 40) { + const domRef = ref(); + const imgCode = ref(''); + + function setImgCode(code: string) { + imgCode.value = code; + } + + function getImgCode() { + if (!domRef.value) return; + imgCode.value = draw(domRef.value, width, height); + } + + onMounted(() => { + getImgCode(); + }); + + return { + domRef, + imgCode, + setImgCode, + getImgCode + }; +} + +function randomNum(min: number, max: number) { + const num = Math.floor(Math.random() * (max - min) + min); + return num; +} + +function randomColor(min: number, max: number) { + const r = randomNum(min, max); + const g = randomNum(min, max); + const b = randomNum(min, max); + return `rgb(${r},${g},${b})`; +} + +function draw(dom: HTMLCanvasElement, width: number, height: number) { + let imgCode = ''; + + const NUMBER_STRING = '0123456789'; + + const ctx = dom.getContext('2d'); + if (!ctx) return imgCode; + + ctx.fillStyle = randomColor(180, 230); + ctx.fillRect(0, 0, width, height); + for (let i = 0; i < 4; i += 1) { + const text = NUMBER_STRING[randomNum(0, NUMBER_STRING.length)]; + imgCode += text; + const fontSize = randomNum(18, 41); + const deg = randomNum(-30, 30); + ctx.font = `${fontSize}px Simhei`; + ctx.textBaseline = 'top'; + ctx.fillStyle = randomColor(80, 150); + ctx.save(); + ctx.translate(30 * i + 23, 15); + ctx.rotate((deg * Math.PI) / 180); + ctx.fillText(text, -15 + 5, -15); + ctx.restore(); + } + for (let i = 0; i < 5; i += 1) { + ctx.beginPath(); + ctx.moveTo(randomNum(0, width), randomNum(0, height)); + ctx.lineTo(randomNum(0, width), randomNum(0, height)); + ctx.strokeStyle = randomColor(180, 230); + ctx.closePath(); + ctx.stroke(); + } + for (let i = 0; i < 41; i += 1) { + ctx.beginPath(); + ctx.arc(randomNum(0, width), randomNum(0, height), 1, 0, 2 * Math.PI); + ctx.closePath(); + ctx.fillStyle = randomColor(150, 200); + ctx.fill(); + } + return imgCode; +} diff --git a/src/hooks/business/useSmsCode.ts b/src/hooks/business/useSmsCode.ts new file mode 100644 index 00000000..f1478589 --- /dev/null +++ b/src/hooks/business/useSmsCode.ts @@ -0,0 +1,59 @@ +import { computed } from 'vue'; +import { REGEXP_PHONE } from '@/config'; +import { fetchSmsCode } from '@/service'; +import { useLoading } from '../common'; +import useCountDown from './useCountDown'; + +export default function useSmsCode() { + const { loading, startLoading, endLoading } = useLoading(); + const { counts, start, isCounting } = useCountDown(60); + const initLabel = '获取验证码'; + const countingLabel = (second: number) => `${second}秒后重新获取`; + const label = computed(() => { + let text = initLabel; + if (loading.value) { + text = ''; + } + if (isCounting.value) { + text = countingLabel(counts.value); + } + return text; + }); + + /** 判断手机号码格式是否正确 */ + function isPhoneValid(phone: string) { + let valid = true; + if (phone.trim() === '') { + window.$message?.error('手机号码不能为空!'); + valid = false; + } else if (!REGEXP_PHONE.test(phone)) { + window.$message?.error('手机号码格式错误!'); + valid = false; + } + return valid; + } + + /** + * 获取短信验证码 + * @param phone - 手机号 + */ + async function getSmsCode(phone: string) { + const valid = isPhoneValid(phone); + if (!valid || loading.value) return; + startLoading(); + const { data } = await fetchSmsCode(phone); + if (data) { + window.$message?.success('验证码发送成功!'); + start(); + } + endLoading(); + } + + return { + label, + start, + isCounting, + getSmsCode, + loading + }; +} diff --git a/src/hooks/index.ts b/src/hooks/index.ts index d0b93236..5f193c38 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -1 +1,2 @@ export * from './common'; +export * from './business'; diff --git a/src/interface/enum.ts b/src/interface/enum.ts index 9fc9e789..646adb97 100644 --- a/src/interface/enum.ts +++ b/src/interface/enum.ts @@ -2,5 +2,3 @@ import { EnumLoginModule } from '@/enum'; /** 登录模块 */ export type LoginModuleKey = keyof typeof EnumLoginModule; - -export type LoginModuleRegexp = LoginModuleKey; diff --git a/src/router/guard/permission.ts b/src/router/guard/permission.ts index 7734075b..4eea1734 100644 --- a/src/router/guard/permission.ts +++ b/src/router/guard/permission.ts @@ -15,7 +15,7 @@ export async function handlePagePermission( const permissions = to.meta.permissions || []; const needLogin = Boolean(to.meta?.requiresAuth) || Boolean(permissions.length); - const hasPermission = !permissions.length || permissions.includes(auth.role); + const hasPermission = !permissions.length || permissions.includes(auth.userInfo.userRole); if (!route.isAddedDynamicRoute) { // 添加动态路由 diff --git a/src/router/routes/constant.ts b/src/router/routes/constant.ts index d92ca805..b03b2665 100644 --- a/src/router/routes/constant.ts +++ b/src/router/routes/constant.ts @@ -1,4 +1,5 @@ -// import { getLoginModuleRegExp } from '@/utils'; +import { getLoginModuleRegExp } from '@/utils'; +import type { LoginModuleKey } from '@/interface'; /** 固定的路由 */ const constantRoutes: AuthRoute.Route[] = [ @@ -12,8 +13,14 @@ const constantRoutes: AuthRoute.Route[] = [ }, { name: 'login', - path: '/login', + path: `/login/:module(${getLoginModuleRegExp()})?`, component: 'blank', + props: route => { + const moduleType = (route.params.module as LoginModuleKey) || 'pwd-login'; + return { + module: moduleType + }; + }, meta: { title: '登录', single: true diff --git a/src/service/api/auth.ts b/src/service/api/auth.ts index 2786deb6..2e6e6f04 100644 --- a/src/service/api/auth.ts +++ b/src/service/api/auth.ts @@ -1,15 +1,39 @@ import { mockRequest } from '../request'; import { userRoutesMiddleware } from '../middleware'; +/** + * 获取验证码 + * @param phone - 手机号 + * @returns - 返回boolean值表示是否发送成功 + */ +export function fetchSmsCode(phone: string) { + return mockRequest.post('/getSmsCode', { phone }); +} + +/** + * 登录 + * @param phone - 手机号 + * @param pwdOrCode - 密码或验证码 + * @param type - 登录方式: pwd - 密码登录; sms - 验证码登录 + */ +export function fetchLogin(phone: string, pwdOrCode: string, type: 'pwd' | 'sms') { + if (type === 'pwd') { + return mockRequest.post('/loginByPwd', { phone, pwd: pwdOrCode }); + } + return mockRequest.post('/loginByCode', { phone, code: pwdOrCode }); +} + +/** 获取用户信息 */ +export function fetchUserInfo() { + return mockRequest.get('/getUserInfo'); +} + /** * 获取用户路由数据 * @param userId - 用户id * @description 后端根据用户id查询到对应的角色类型,并将路由筛选出对应角色的路由数据返回前端 */ export async function fetchUserRoutes(userId: string = 'soybean') { - const { data } = await mockRequest( - { url: '/getUserRoutes', method: 'post', data: { userId } }, - false - ); + const { data } = await mockRequest.post('/getUserRoutes', { userId }); return userRoutesMiddleware(data); } diff --git a/src/service/middleware/auth.ts b/src/service/middleware/auth.ts index 8e2296ea..78302dd7 100644 --- a/src/service/middleware/auth.ts +++ b/src/service/middleware/auth.ts @@ -1,7 +1,7 @@ import type { RouteRecordRaw } from 'vue-router'; import { transformAuthRouteToVueRoute } from '@/utils'; -export function userRoutesMiddleware(data: ApiRoute.ResponseRoute | null) { +export function userRoutesMiddleware(data: ApiRoute.Route | null) { if (!data) return []; const routes: RouteRecordRaw[] = data.routes.map(item => transformAuthRouteToVueRoute(item)); diff --git a/src/service/request/request.ts b/src/service/request/request.ts index 5329d849..9c9eb391 100644 --- a/src/service/request/request.ts +++ b/src/service/request/request.ts @@ -6,13 +6,6 @@ import CustomAxiosInstance from './instance'; type RequestMethod = 'get' | 'post' | 'put' | 'delete'; -type RequestResultHook = { - data: Ref; - error: Ref; - loading: Ref; - network: Ref; -}; - interface RequestParam { url: string; method?: RequestMethod; @@ -20,9 +13,95 @@ interface RequestParam { axiosConfig?: AxiosRequestConfig; } +/** + * 创建请求 + * @param axiosConfig - axios配置 + */ export function createRequest(axiosConfig: AxiosRequestConfig) { const customInstance = new CustomAxiosInstance(axiosConfig); + /** + * 异步promise请求 + * @param param - 请求参数 + * - url: 请求地址 + * - method: 请求方法(默认get) + * - data: 请求的body的data + * - axiosConfig: axios配置 + */ + async function asyncRequest(param: RequestParam): Promise> { + const { url } = param; + const method = param.method || 'get'; + const { instance } = customInstance; + const res = (await getRequestResponse( + instance, + method, + url, + param.data, + param.axiosConfig + )) as Service.RequestResult; + + return res; + } + + /** + * get请求 + * @param url - 请求地址 + * @param config - axios配置 + */ + function get(url: string, config?: AxiosRequestConfig) { + return asyncRequest({ url, method: 'get', axiosConfig: config }); + } + + /** + * post请求 + * @param url - 请求地址 + * @param data - 请求的body的data + * @param config - axios配置 + */ + function post(url: string, data?: any, config?: AxiosRequestConfig) { + return asyncRequest({ url, method: 'post', data, axiosConfig: config }); + } + /** + * put请求 + * @param url - 请求地址 + * @param data - 请求的body的data + * @param config - axios配置 + */ + function put(url: string, data?: any, config?: AxiosRequestConfig) { + return asyncRequest({ url, method: 'put', data, axiosConfig: config }); + } + + /** + * delete请求 + * @param url - 请求地址 + * @param config - axios配置 + */ + function handleDelete(url: string, config: AxiosRequestConfig) { + return asyncRequest({ url, method: 'delete', axiosConfig: config }); + } + + return { + get, + post, + put, + delete: handleDelete + }; +} + +type RequestResultHook = { + data: Ref; + error: Ref; + loading: Ref; + network: Ref; +}; + +/** + * 创建hooks请求 + * @param axiosConfig - axios配置 + */ +export function createHookRequest(axiosConfig: AxiosRequestConfig) { + const customInstance = new CustomAxiosInstance(axiosConfig); + /** * hooks请求 * @param param - 请求参数 @@ -30,70 +109,82 @@ export function createRequest(axiosConfig: AxiosRequestConfig) { * - method: 请求方法(默认get) * - data: 请求的body的data * - axiosConfig: axios配置 - * @param hookMode - 是否启用hook写法 */ - function request(param: RequestParam, hookMode: true): RequestResultHook; - function request(param: RequestParam, hookMode: false): Promise>; - function request( - param: RequestParam, - hookMode: boolean - ): RequestResultHook | Promise> { + function useRequest(param: RequestParam): RequestResultHook { + const { loading, startLoading, endLoading } = useLoading(); + const { bool: network, setBool: setNetwork } = useBoolean(window.navigator.onLine); + + startLoading(); + const data = ref(null) as Ref; + const error = ref(null); + + function handleRequestResult(response: any) { + const res = response as Service.RequestResult; + data.value = res.data; + error.value = res.error; + endLoading(); + setNetwork(window.navigator.onLine); + } + const { url } = param; const method = param.method || 'get'; const { instance } = customInstance; - if (hookMode) { - return useRequest(instance, method, url, param.data, param.axiosConfig); - } - return asyncRequest(instance, method, url, param.data, param.axiosConfig); + + getRequestResponse(instance, method, url, param.data, param.axiosConfig).then(handleRequestResult); + + return { + data, + error, + loading, + network + }; } - return request; -} - -function useRequest( - instance: AxiosInstance, - method: RequestMethod, - url: string, - bodyData?: any, - config?: AxiosRequestConfig -): RequestResultHook { - const { loading, startLoading, endLoading } = useLoading(); - const { bool: network, setBool: setNetwork } = useBoolean(window.navigator.onLine); - - startLoading(); - const data = ref(null) as Ref; - const error = ref(null); - - function handleRequestResult(response: any) { - const res = response as Service.RequestResult; - data.value = res.data; - error.value = res.error; - endLoading(); - setNetwork(window.navigator.onLine); + /** + * get请求 + * @param url - 请求地址 + * @param config - axios配置 + */ + function get(url: string, config?: AxiosRequestConfig) { + return useRequest({ url, method: 'get', axiosConfig: config }); } - getRequestResponse(instance, method, url, bodyData, config).then(handleRequestResult); + /** + * post请求 + * @param url - 请求地址 + * @param data - 请求的body的data + * @param config - axios配置 + */ + function post(url: string, data?: any, config?: AxiosRequestConfig) { + return useRequest({ url, method: 'post', data, axiosConfig: config }); + } + /** + * put请求 + * @param url - 请求地址 + * @param data - 请求的body的data + * @param config - axios配置 + */ + function put(url: string, data?: any, config?: AxiosRequestConfig) { + return useRequest({ url, method: 'put', data, axiosConfig: config }); + } + + /** + * delete请求 + * @param url - 请求地址 + * @param config - axios配置 + */ + function handleDelete(url: string, config: AxiosRequestConfig) { + return useRequest({ url, method: 'delete', axiosConfig: config }); + } return { - data, - error, - loading, - network + get, + post, + put, + delete: handleDelete }; } -async function asyncRequest( - instance: AxiosInstance, - method: RequestMethod, - url: string, - bodyData?: any, - config?: AxiosRequestConfig -): Promise> { - const res = (await getRequestResponse(instance, method, url, bodyData, config)) as Service.RequestResult; - - return res; -} - async function getRequestResponse( instance: AxiosInstance, method: RequestMethod, diff --git a/src/store/modules/auth/index.ts b/src/store/modules/auth/index.ts index f99994bd..31e86bea 100644 --- a/src/store/modules/auth/index.ts +++ b/src/store/modules/auth/index.ts @@ -1,7 +1,11 @@ -import { ref, computed, reactive } from 'vue'; +import { ref, computed, reactive, unref } from 'vue'; import type { Ref, ComputedRef } from 'vue'; import { defineStore } from 'pinia'; -import { getUserInfo, getToken } from '@/utils'; +import { router as globalRouter } from '@/router'; +import { useRouterPush, useRouteQuery } from '@/composables'; +import { useLoading } from '@/hooks'; +import { fetchLogin, fetchUserInfo } from '@/service'; +import { getUserInfo, getToken, setUserInfo, setToken, setRefreshToken, clearAuthStorage } from '@/utils'; interface AuthStore { /** 用户信息 */ @@ -10,21 +14,94 @@ interface AuthStore { token: Ref; /** 是否登录 */ isLogin: ComputedRef; - /** 用户角色 */ - role: Ref; + /** + * 重置authStore + * 是否需要跳转页面(例如当前页面是需要权限的,登出后需要跳转到登录页面) + */ + resetAuthStore(pushRoute: boolean): void; + /** 登录的加载状态 */ + loginLoding: Ref; + /** + * 登录 + * @param phone - 手机号 + * @param pwdOrCode - 密码或验证码 + * @param type - 登录方式: pwd - 密码登录; sms - 验证码登录 + */ + login(phone: string, pwdOrCode: string, type: 'pwd' | 'sms'): void; } export const useAuthStore = defineStore('auth-store', () => { + const { toLogin, toLoginRedirect } = useRouterPush(false); + const { loginRedirect } = useRouteQuery(false); + const { loading: loginLoding, startLoading: startLoginLoading, endLoading: endLoginLoading } = useLoading(); + const userInfo: Auth.UserInfo = reactive(getUserInfo()); + function handleSetUserInfo(data: Auth.UserInfo) { + Object.assign(userInfo, data); + } + const token = ref(getToken()); + function handleSetToken(data: string) { + token.value = data; + } + const isLogin = computed(() => Boolean(token.value)); - const role = ref('super'); + + function resetAuthStore(pushRoute: boolean = true) { + const auth = useAuthStore(); + const route = unref(globalRouter.currentRoute); + + clearAuthStorage(); + auth.$reset(); + + if (pushRoute && route.meta.requiresAuth) { + toLogin(); + } + } + + async function login(phone: string, pwdOrCode: string, type: 'pwd' | 'sms') { + startLoginLoading(); + const { data } = await fetchLogin(phone, pwdOrCode, type); + if (data) { + await loginByToken(data); + } + endLoginLoading(); + } + + async function loginByToken(backendToken: ApiAuth.Token) { + // 1.先把token存储到缓存中 + const { token, refreshToken } = backendToken; + setToken(token); + setRefreshToken(refreshToken); + + // 2.获取用户信息 + const { data } = await fetchUserInfo(); + if (data) { + // 成功后把用户信息存储到缓存中 + setUserInfo(data); + handleSetToken(token); + handleSetUserInfo(data); + // 3. 跳转登录后的地址 + toLoginRedirect(loginRedirect.value); + // 4.登录成功弹出欢迎提示 + window.$notification?.success({ + title: '登录成功!', + content: `欢迎回来,${userInfo.userName}!`, + duration: 3000 + }); + } else { + // 不成功则重置状态 + resetAuthStore(false); + } + } const authStore: AuthStore = { userInfo, token, isLogin, - role + resetAuthStore, + loginLoding, + login }; return authStore; diff --git a/src/store/modules/route/index.ts b/src/store/modules/route/index.ts index 22c18d64..f7e2277d 100644 --- a/src/store/modules/route/index.ts +++ b/src/store/modules/route/index.ts @@ -26,7 +26,7 @@ interface RouteStore { * 获取路由路径 * @description getRouteName 和 getRoutePath 优先使用 getRouteName */ - getRoutePath(key: AuthRoute.RouteKey): AuthRoute.RoutePath<''> | undefined; + getRoutePath(key: AuthRoute.RouteKey): AuthRoute.RoutePath | undefined; /** 获取路由路径 */ getRouteTitle(key: AuthRoute.RouteKey): string | undefined; } diff --git a/src/store/modules/theme/helpers.ts b/src/store/modules/theme/helpers.ts index 9de1f417..4369a6b2 100644 --- a/src/store/modules/theme/helpers.ts +++ b/src/store/modules/theme/helpers.ts @@ -37,3 +37,27 @@ export function getThemeColors(colors: [ColorType, string][]) { return themeColor; } + +/** windicss 暗黑模式 */ +export function handleWindicssDarkMode() { + const DARK_CLASS = 'dark'; + function getHtmlElement() { + return document.querySelector('html'); + } + function addDarkClass() { + const html = getHtmlElement(); + if (html) { + html.classList.add(DARK_CLASS); + } + } + function removeDarkClass() { + const html = getHtmlElement(); + if (html) { + html.classList.remove(DARK_CLASS); + } + } + return { + addDarkClass, + removeDarkClass + }; +} diff --git a/src/store/modules/theme/index.ts b/src/store/modules/theme/index.ts index 6577a84c..4e474463 100644 --- a/src/store/modules/theme/index.ts +++ b/src/store/modules/theme/index.ts @@ -1,11 +1,12 @@ -import { ref, computed } from 'vue'; +import { ref, computed, watch } from 'vue'; import type { Ref, ComputedRef } from 'vue'; import { defineStore } from 'pinia'; -import { useThemeVars } from 'naive-ui'; -import type { GlobalThemeOverrides } from 'naive-ui'; +import { useThemeVars, darkTheme, useOsTheme } from 'naive-ui'; +import type { GlobalThemeOverrides, GlobalTheme } from 'naive-ui'; import { kebabCase } from 'lodash-es'; +import { useBoolean } from '@/hooks'; import { getColorPalette } from '@/utils'; -import { getThemeColors } from './helpers'; +import { getThemeColors, handleWindicssDarkMode } from './helpers'; interface OtherColor { /** 信息 */ @@ -18,19 +19,31 @@ interface OtherColor { error: string; } +type BuiltInGlobalTheme = Omit, 'InternalSelectMenu' | 'InternalSelection'>; + interface ThemeStore { + /** 暗黑模式 */ + darkMode: Ref; + /** 设置暗黑模式 */ + setDarkMode(dark: boolean): void; + /** 切换/关闭 暗黑模式 */ + toggleDarkMode(dark: boolean): void; /** 主题颜色 */ themeColor: Ref; /** 其他颜色 */ otherColor: ComputedRef; /** naiveUI的主题配置 */ naiveThemeOverrides: ComputedRef; + /** naive-ui暗黑主题 */ + naiveTheme: ComputedRef; } type ThemeVarsKeys = keyof Exclude; export const useThemeStore = defineStore('theme-store', () => { const themeVars = useThemeVars(); + const { bool: darkMode, setBool: setDarkMode, toggle: toggleDarkMode } = useBoolean(); + const { addDarkClass, removeDarkClass } = handleWindicssDarkMode(); const themeColor = ref('#1890ff'); const otherColor = computed(() => ({ @@ -62,6 +75,12 @@ export const useThemeStore = defineStore('theme-store', () => { }; }); + /** naive-ui暗黑主题 */ + const naiveTheme = computed(() => (darkMode.value ? darkTheme : undefined)); + + /** 操作系统暗黑主题 */ + const osTheme = useOsTheme(); + /** 添加css vars至html */ function addThemeCssVarsToHtml() { if (document.documentElement.style.cssText) return; @@ -82,10 +101,40 @@ export const useThemeStore = defineStore('theme-store', () => { init(); + // 监听操作系统主题模式 + watch( + osTheme, + newValue => { + const isDark = newValue === 'dark'; + if (isDark) { + setDarkMode(true); + } else { + setDarkMode(false); + } + }, + { immediate: true } + ); + // 监听主题的暗黑模式 + watch( + () => darkMode.value, + newValue => { + if (newValue) { + addDarkClass(); + } else { + removeDarkClass(); + } + }, + { immediate: true } + ); + const themeStore: ThemeStore = { + darkMode, + setDarkMode, + toggleDarkMode, themeColor, otherColor, - naiveThemeOverrides + naiveThemeOverrides, + naiveTheme }; return themeStore; diff --git a/src/typings/api/auth.d.ts b/src/typings/api/auth.d.ts new file mode 100644 index 00000000..e2ede969 --- /dev/null +++ b/src/typings/api/auth.d.ts @@ -0,0 +1,10 @@ +/** 后端返回的用户权益相关类型 */ +declare namespace ApiAuth { + /** 返回的token和刷新token */ + interface Token { + token: string; + refreshToken: string; + } + /** 返回的用户信息 */ + type UserInfo = Auth.UserInfo; +} diff --git a/src/typings/api/route.d.ts b/src/typings/api/route.d.ts index dcd457b0..fccb882e 100644 --- a/src/typings/api/route.d.ts +++ b/src/typings/api/route.d.ts @@ -1,7 +1,7 @@ /** 后端返回的路由相关类型 */ declare namespace ApiRoute { /** 后端返回的路由数据类型 */ - interface ResponseRoute { + interface Route { /** 动态路由 */ routes: AuthRoute.Route[]; /** 路由首页对应的key */ diff --git a/src/typings/business/auth.d.ts b/src/typings/business/auth.d.ts index 7e6b36b8..00959a4b 100644 --- a/src/typings/business/auth.d.ts +++ b/src/typings/business/auth.d.ts @@ -1,15 +1,5 @@ /** 用户相关模块 */ declare namespace Auth { - /** 用户信息 */ - interface UserInfo { - /** 用户id */ - userId: string; - /** 用户名 */ - userName: string; - /** 用户手机号 */ - userPhone: string; - } - /** * 用户角色类型 * - super: 超级管理员 @@ -18,4 +8,16 @@ declare namespace Auth { * - visitor: 游客 */ type RoleType = 'super' | 'admin' | 'test' | 'visitor'; + + /** 用户信息 */ + interface UserInfo { + /** 用户id */ + userId: string; + /** 用户名 */ + userName: string; + /** 用户手机号 */ + userPhone: string; + /** 用户角色类型 */ + userRole: RoleType; + } } diff --git a/src/typings/common/route.d.ts b/src/typings/common/route.d.ts index 498df82f..0db524da 100644 --- a/src/typings/common/route.d.ts +++ b/src/typings/common/route.d.ts @@ -24,7 +24,7 @@ declare namespace AuthRoute { : `/${Key}`; /** 路由路径 */ - type RoutePath = + type RoutePath = | '/' | Exclude, '/root' | '/redirect'> | Key @@ -65,8 +65,11 @@ declare namespace AuthRoute { order?: number; }; + /** 登录路由路径 */ + type LoginPath = `/login/:module(${string})?`; + /** 单个路由的类型结构(后端返回此类型结构的路由) */ - interface Route { + interface Route { /** 路由名称(路由唯一标识) */ name: RouteKey; /** 路由路径 */ @@ -85,5 +88,7 @@ declare namespace AuthRoute { children?: Route[]; /** 路由描述 */ meta: RouteMeta; + /** 属性 */ + props?: boolean | Record | ((to: any) => Record); } } diff --git a/src/typings/common/util.d.ts b/src/typings/common/util.d.ts index 7e9b1931..f2fb7eda 100644 --- a/src/typings/common/util.d.ts +++ b/src/typings/common/util.d.ts @@ -12,6 +12,4 @@ declare namespace Util { type UnionToTuple = [T] extends [never] ? [] : [LastInUnion, ...UnionToTuple>>]; - - type Inter = UnionToTuple<'1' | '2'>; } diff --git a/src/utils/auth/user.ts b/src/utils/auth/user.ts index 898e11e2..03bf976b 100644 --- a/src/utils/auth/user.ts +++ b/src/utils/auth/user.ts @@ -36,7 +36,8 @@ export function getUserInfo() { const emptyInfo: Auth.UserInfo = { userId: '', userName: '', - userPhone: '' + userPhone: '', + userRole: 'visitor' }; const userInfo: Auth.UserInfo = getLocal(EnumStorageKey['user-info']) || emptyInfo; return userInfo; diff --git a/src/utils/common/index.ts b/src/utils/common/index.ts index 72ad0c66..9cd5747f 100644 --- a/src/utils/common/index.ts +++ b/src/utils/common/index.ts @@ -1,4 +1,5 @@ export * from './typeof'; export * from './console'; export * from './color'; +export * from './number'; export * from './design-pattern'; diff --git a/src/utils/common/number.ts b/src/utils/common/number.ts new file mode 100644 index 00000000..4bd5de49 --- /dev/null +++ b/src/utils/common/number.ts @@ -0,0 +1,23 @@ +/** + * 根据数字获取对应的汉字 + * @param num - 数字(0-10) + */ +export function getHanByNumber(num: number) { + const HAN_STR = '零一二三四五六七八九十'; + return HAN_STR.charAt(num); +} + +/** + * 将总秒数转换成 分:秒 + * @param seconds - 秒 + */ +export function transformToTimeCountDown(seconds: number) { + const SECONDS_A_MINUTE = 60; + function fillZero(num: number) { + return num.toString().padStart(2, '0'); + } + const minuteNum = Math.floor(seconds / SECONDS_A_MINUTE); + const minute = fillZero(minuteNum); + const second = fillZero(seconds - minuteNum * SECONDS_A_MINUTE); + return `${minute}: ${second}`; +} diff --git a/src/utils/form/index.ts b/src/utils/form/index.ts new file mode 100644 index 00000000..0a15f57b --- /dev/null +++ b/src/utils/form/index.ts @@ -0,0 +1 @@ +export * from './rule'; diff --git a/src/utils/form/rule.ts b/src/utils/form/rule.ts new file mode 100644 index 00000000..5587db33 --- /dev/null +++ b/src/utils/form/rule.ts @@ -0,0 +1,73 @@ +import { Ref } from 'vue'; +import type { FormItemRule } from 'naive-ui'; +import { REGEXP_PHONE, REGEXP_PWD, REGEXP_CODE_SIX, REGEXP_EMAIL } from '@/config'; + +/** 表单规则 */ +interface CustomFormRules { + /** 手机号码 */ + phone: FormItemRule[]; + /** 密码 */ + pwd: FormItemRule[]; + /** 验证码 */ + code: FormItemRule[]; + /** 邮箱 */ + email: FormItemRule[]; +} + +/** 表单规则 */ +export const formRules: CustomFormRules = { + phone: [ + { required: true, message: '请输入手机号码' }, + { pattern: REGEXP_PHONE, message: '手机号码格式错误', trigger: 'input' } + ], + pwd: [ + { required: true, message: '请输入密码' }, + { pattern: REGEXP_PWD, message: '密码为8-18位数字/字符/符号,至少2种组合', trigger: 'input' } + ], + code: [ + { required: true, message: '请输入验证码' }, + { pattern: REGEXP_CODE_SIX, message: '验证码格式错误', trigger: 'input' } + ], + email: [{ pattern: REGEXP_EMAIL, message: '邮箱格式错误', trigger: 'blur' }] +}; + +/** 获取确认密码的表单规则 */ +export function getConfirmPwdRule(pwd: Ref) { + const confirmPwdRule: FormItemRule[] = [ + { required: true, message: '请输入确认密码' }, + { + validator: (rule, value) => { + if (!isBlankString(value) && value !== pwd.value) { + return Promise.reject(rule.message); + } + return Promise.resolve(); + }, + message: '输入的值与密码不一致', + trigger: 'input' + } + ]; + return confirmPwdRule; +} + +/** 获取图片验证码的表单规则 */ +export function getImgCodeRule(imgCode: Ref) { + const imgCodeRule: FormItemRule[] = [ + { required: true, message: '请输入验证码' }, + { + validator: (rule, value) => { + if (!isBlankString(value) && value !== imgCode.value) { + return Promise.reject(rule.message); + } + return Promise.resolve(); + }, + message: '验证码不正确', + trigger: 'blur' + } + ]; + return imgCodeRule; +} + +/** 是否为空字符串 */ +function isBlankString(str: string) { + return str.trim() === ''; +} diff --git a/src/utils/index.ts b/src/utils/index.ts index 7d838cc4..cc3d8ff7 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -3,3 +3,4 @@ export * from './storage'; export * from './service'; export * from './auth'; export * from './router'; +export * from './form'; diff --git a/src/utils/router/helpers.ts b/src/utils/router/helpers.ts index 2c3762d0..5645acfd 100644 --- a/src/utils/router/helpers.ts +++ b/src/utils/router/helpers.ts @@ -40,12 +40,18 @@ export function transformAuthRouteToVueRoute(item: AuthRoute.Route) { consoleError('路由组件解析失败: ', item); } } + + if (hasProps(item) && !isSingleRoute(item)) { + (itemRoute as any).props = item.props; + } + if (isSingleRoute(item)) { itemRoute.children = [ { path: '', name: item.name, - component: getViewComponent(item.name) + component: getViewComponent(item.name), + props: hasProps(item) ? item.props : undefined } ]; } else if (hasChildren(item)) { @@ -67,6 +73,10 @@ function hasChildren(item: AuthRoute.Route) { return Boolean(item.children && item.children.length); } +function hasProps(item: AuthRoute.Route) { + return Boolean(item.props); +} + function isSingleRoute(item: AuthRoute.Route) { return Boolean(item.meta.single); } diff --git a/src/views/system/login/components/BindWechat/index.vue b/src/views/system/login/components/BindWechat/index.vue new file mode 100644 index 00000000..d93c0b3e --- /dev/null +++ b/src/views/system/login/components/BindWechat/index.vue @@ -0,0 +1,61 @@ + + + + diff --git a/src/views/system/login/components/CodeLogin/index.vue b/src/views/system/login/components/CodeLogin/index.vue new file mode 100644 index 00000000..1176ec4b --- /dev/null +++ b/src/views/system/login/components/CodeLogin/index.vue @@ -0,0 +1,81 @@ + + + + diff --git a/src/views/system/login/components/LoginBg/index.vue b/src/views/system/login/components/LoginBg/index.vue index fdff871c..69a7f48b 100644 --- a/src/views/system/login/components/LoginBg/index.vue +++ b/src/views/system/login/components/LoginBg/index.vue @@ -1,5 +1,5 @@