From 9143fcdfc8b0c934d17523d6ab9fd27f316f24c5 Mon Sep 17 00:00:00 2001 From: zhangwei <1504152376@qq.com> Date: 星期三, 18 六月 2025 09:35:01 +0800 Subject: [PATCH] - --- src/components/RePureTableBar/src/bar.tsx | 393 src/plugins/elementPlus.ts | 248 src/router/modules/error.ts | 36 src/assets/home/share.png | 0 src/layout/index.vue | 235 src/store/types.ts | 47 src/layout/components/lay-sidebar/components/SidebarLinkItem.vue | 32 src/layout/hooks/useNav.ts | 157 .husky/commit-msg | 8 mock/login.ts | 42 src/assets/iconfont/iconfont.woff2 | 0 src/router/modules/remaining.ts | 40 src/layout/components/lay-sidebar/components/SidebarLeftCollapse.vue | 69 src/views/error/404.vue | 70 src/assets/svg/enter_outlined.svg | 1 .npmrc | 4 .env.development | 8 src/assets/home/vue.svg | 1 .vscode/vue3.0.code-snippets | 22 src/style/element-plus.scss | 189 types/shims-tsx.d.ts | 24 src/layout/components/lay-sidebar/components/SidebarFullScreen.vue | 30 src/assets/home/xian.png | 0 src/style/tailwind.css | 46 src/utils/localforage/types.d.ts | 166 src/assets/table-bar/collapse.svg | 1 src/views/login/index.vue | 180 src/directives/ripple/index.scss | 48 src/assets/svg/keyboard_esc.svg | 1 vite.config.ts | 62 src/assets/svg/dark.svg | 1 src/layout/components/lay-search/components/SearchHistory.vue | 198 src/layout/components/lay-sidebar/components/SidebarLogo.vue | 72 src/router/modules/home.ts | 25 .husky/pre-commit | 10 src/components/ReSegmented/src/type.ts | 20 src/views/permission/button/perms.vue | 109 src/components/ReSegmented/index.ts | 8 src/utils/responsive.ts | 42 src/assets/login/illustration.svg | 1 src/utils/progress/index.ts | 17 src/assets/status/500.svg | 1 .markdownlint.json | 11 src/store/modules/user.ts | 109 src/assets/status/404.svg | 1 src/assets/svg/full_screen.svg | 1 src/main.ts | 64 src/components/ReIcon/index.ts | 12 src/layout/hooks/useTag.ts | 245 src/layout/components/lay-notice/components/NoticeList.vue | 23 src/assets/table-bar/refresh.svg | 1 src/components/ReSegmented/src/index.tsx | 216 src/layout/components/lay-tag/components/TagChrome.vue | 33 src/api/routes.ts | 10 src/assets/table-bar/expand.svg | 1 src/layout/components/lay-search/components/SearchModal.vue | 334 src/layout/types.ts | 92 src/layout/components/lay-sidebar/components/SidebarTopCollapse.vue | 33 src/store/modules/epTheme.ts | 49 src/components/ReAuth/src/auth.tsx | 20 src/layout/frame.vue | 91 src/layout/components/lay-sidebar/components/SidebarCenterCollapse.vue | 70 .stylelintignore | 4 src/layout/components/lay-notice/components/NoticeItem.vue | 177 src/utils/localforage/index.ts | 109 index.html | 84 src/assets/home/BellFilled.png | 0 src/style/dark.scss | 182 src/components/RePerms/src/perms.tsx | 20 src/layout/components/lay-sidebar/NavMix.vue | 143 LICENSE | 21 mock/refreshToken.ts | 27 src/views/login/utils/static.ts | 5 src/layout/components/lay-frame/index.vue | 79 src/components/ReIcon/src/iconifyIconOffline.ts | 47 src/directives/index.ts | 6 src/utils/mitt.ts | 14 src/components/ReSegmented/src/index.css | 156 types/shims-vue.d.ts | 11 build/utils.ts | 110 src/layout/components/lay-navbar/index.vue | 135 src/views/error/403.vue | 70 src/layout/hooks/useBoolean.ts | 26 tsconfig.json | 55 src/layout/hooks/useDataThemeChange.ts | 138 src/utils/auth.ts | 141 src/directives/auth/index.ts | 15 stylelint.config.js | 87 src/assets/svg/day.svg | 1 src/components/ReDialog/type.ts | 275 .lintstagedrc | 20 postcss.config.js | 8 build/optimize.ts | 29 src/assets/table-bar/drag.svg | 1 build/cdn.ts | 55 types/global-components.d.ts | 135 .gitignore | 22 src/style/theme.scss | 95 src/components/ReDialog/index.vue | 206 src/layout/components/lay-tag/index.scss | 371 src/utils/http/index.ts | 194 src/assets/iconfont/iconfont.js | 68 src/directives/longpress/index.ts | 63 src/style/transition.scss | 54 src/assets/iconfont/iconfont.woff | 0 src/components/RePerms/index.ts | 5 src/layout/components/lay-notice/index.vue | 96 src/assets/home/car.png | 0 src/layout/components/lay-search/types.ts | 20 src/views/welcome/index.vue | 9 src/layout/components/lay-search/components/SearchFooter.vue | 61 src/layout/hooks/useMultiFrame.ts | 25 .vscode/settings.json | 43 src/style/login.css | 96 src/components/ReIcon/src/types.ts | 20 src/layout/components/lay-tag/index.vue | 684 + src/components/ReText/index.ts | 7 src/layout/components/lay-search/index.vue | 21 package.json | 159 src/App.vue | 26 src/layout/components/lay-sidebar/NavVertical.vue | 137 src/router/utils.ts | 410 + .prettierrc.js | 9 public/platform-config.json | 26 src/assets/home/logo.png | 0 src/layout/components/lay-panel/index.vue | 145 src/store/utils.ts | 28 src/components/ReAuth/index.ts | 5 src/components/ReCol/index.ts | 29 src/assets/iconfont/iconfont.css | 27 src/style/sidebar.scss | 719 + build/compress.ts | 63 .vscode/extensions.json | 19 src/components/ReIcon/src/offlineIcon.ts | 23 src/store/modules/permission.ts | 74 src/style/index.scss | 37 src/layout/components/lay-footer/index.vue | 31 src/plugins/echarts.ts | 44 types/index.d.ts | 80 src/components/RePureTableBar/index.ts | 5 src/utils/message.ts | 89 types/directives.d.ts | 28 src/utils/tree.ts | 188 src/utils/globalPolyfills.ts | 7 src/assets/svg/back_top.svg | 1 src/layout/components/lay-sidebar/components/SidebarBreadCrumb.vue | 120 src/views/home/index.vue | 510 + build/info.ts | 57 src/utils/sso.ts | 59 .husky/common.sh | 9 src/components/ReIcon/src/iconifyIconOnline.ts | 31 src/layout/components/lay-setting/index.vue | 631 + src/directives/copy/index.ts | 33 src/components/ReText/src/index.vue | 69 src/assets/table-bar/settings.svg | 1 src/views/permission/page/index.vue | 66 src/layout/redirect.vue | 24 src/directives/perms/index.ts | 15 src/store/modules/multiTags.ts | 145 src/views/login/utils/motion.ts | 40 src/assets/home/banner.png | 0 src/components/ReIcon/src/hooks.ts | 63 mock/asyncRoutes.ts | 69 src/utils/print.ts | 223 src/style/reset.scss | 250 build/plugins.ts | 66 src/views/permission/button/index.vue | 99 src/store/modules/app.ts | 85 src/views/login/utils/rule.ts | 28 src/utils/preventDefault.ts | 28 public/logo.svg | 1 src/assets/home/notice.png | 0 src/layout/hooks/useLayout.ts | 58 src/assets/home/notice1.png | 0 pnpm-lock.yaml | 7329 ++++++++++++++++++ src/components/ReDialog/index.ts | 69 public/favicon.ico | 0 src/router/index.ts | 211 .editorconfig | 14 src/assets/iconfont/iconfont.json | 30 .dockerignore | 21 src/assets/home/car1.png | 0 src/config/index.ts | 55 src/views/error/500.vue | 70 src/assets/svg/system.svg | 1 src/assets/home/Header.png | 0 src/layout/components/lay-search/components/SearchHistoryItem.vue | 52 src/layout/components/lay-search/components/SearchResult.vue | 113 src/utils/http/types.d.ts | 47 .env.production | 13 src/assets/login/bg.png | 0 src/assets/svg/exit_screen.svg | 1 src/directives/ripple/index.ts | 229 src/layout/components/lay-sidebar/components/SidebarItem.vue | 228 README.en-US.md | 39 src/assets/home/daixie.png | 0 types/router.d.ts | 109 .env.staging | 16 src/layout/components/lay-sidebar/NavHorizontal.vue | 123 src/directives/optimize/index.ts | 68 src/store/modules/settings.ts | 35 eslint.config.js | 173 src/components/ReIcon/src/iconfont.ts | 47 .vscode/vue3.3.code-snippets | 20 .vscode/vue3.2.code-snippets | 17 src/assets/status/403.svg | 1 types/global.d.ts | 193 .env | 5 commitlint.config.js | 35 src/api/user.ts | 45 src/layout/components/lay-content/index.vue | 213 .nvmrc | 1 src/assets/iconfont/iconfont.ttf | 0 src/store/index.ts | 9 Dockerfile | 20 .browserslistrc | 4 src/assets/login/avatar.svg | 1 src/assets/user.jpg | 0 src/layout/components/lay-notice/data.ts | 97 src/utils/propTypes.ts | 39 src/layout/components/lay-sidebar/components/SidebarExtraIcon.vue | 20 221 files changed, 23,628 insertions(+), 0 deletions(-) diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 0000000..40bd99c --- /dev/null +++ b/.browserslistrc @@ -0,0 +1,4 @@ +> 1% +last 2 versions +not dead +not ie 11 \ No newline at end of file diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..0376edd --- /dev/null +++ b/.dockerignore @@ -0,0 +1,21 @@ +node_modules +.DS_Store +dist +dist-ssr +*.local +.eslintcache +report.html + +yarn.lock +npm-debug.log* +.pnpm-error.log* +.pnpm-debug.log +tests/**/coverage/ + +# Editor directories and files +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +tsconfig.tsbuildinfo diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..ea6e20f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# http://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/.env b/.env new file mode 100644 index 0000000..09344c1 --- /dev/null +++ b/.env @@ -0,0 +1,5 @@ +# 骞冲彴鏈湴杩愯绔彛鍙� +VITE_PORT = 8848 + +# 鏄惁闅愯棌棣栭〉 闅愯棌 true 涓嶉殣钘� false 锛堝嬁鍒犻櫎锛孷ITE_HIDE_HOME鍙渶鍦�.env鏂囦欢閰嶇疆锛� +VITE_HIDE_HOME = false diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..90d1146 --- /dev/null +++ b/.env.development @@ -0,0 +1,8 @@ +# 骞冲彴鏈湴杩愯绔彛鍙� +VITE_PORT = 8848 + +# 寮�鍙戠幆澧冭鍙栭厤缃枃浠惰矾寰� +VITE_PUBLIC_PATH = / + +# 寮�鍙戠幆澧冭矾鐢卞巻鍙叉ā寮忥紙Hash妯″紡浼�"hash"銆丠TML5妯″紡浼�"h5"銆丠ash妯″紡甯ase鍙傛暟浼�"hash,base鍙傛暟"銆丠TML5妯″紡甯ase鍙傛暟浼�"h5,base鍙傛暟"锛� +VITE_ROUTER_HISTORY = "hash" diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..84e6086 --- /dev/null +++ b/.env.production @@ -0,0 +1,13 @@ +# 绾夸笂鐜骞冲彴鎵撳寘璺緞 +VITE_PUBLIC_PATH = / + +# 绾夸笂鐜璺敱鍘嗗彶妯″紡锛圚ash妯″紡浼�"hash"銆丠TML5妯″紡浼�"h5"銆丠ash妯″紡甯ase鍙傛暟浼�"hash,base鍙傛暟"銆丠TML5妯″紡甯ase鍙傛暟浼�"h5,base鍙傛暟"锛� +VITE_ROUTER_HISTORY = "hash" + +# 鏄惁鍦ㄦ墦鍖呮椂浣跨敤cdn鏇挎崲鏈湴搴� 鏇挎崲 true 涓嶆浛鎹� false +VITE_CDN = false + +# 鏄惁鍚敤gzip鍘嬬缉鎴朾rotli鍘嬬缉锛堝垎涓ょ鎯呭喌锛屽垹闄ゅ師濮嬫枃浠跺拰涓嶅垹闄ゅ師濮嬫枃浠讹級 +# 鍘嬬缉鏃朵笉鍒犻櫎鍘熷鏂囦欢鐨勯厤缃細gzip銆乥rotli銆乥oth锛堝悓鏃跺紑鍚� gzip 涓� brotli 鍘嬬缉锛夈�乶one锛堜笉寮�鍚帇缂╋紝榛樿锛� +# 鍘嬬缉鏃跺垹闄ゅ師濮嬫枃浠剁殑閰嶇疆锛歡zip-clear銆乥rotli-clear銆乥oth-clear锛堝悓鏃跺紑鍚� gzip 涓� brotli 鍘嬬缉锛夈�乶one锛堜笉寮�鍚帇缂╋紝榛樿锛� +VITE_COMPRESSION = "none" \ No newline at end of file diff --git a/.env.staging b/.env.staging new file mode 100644 index 0000000..65b57e3 --- /dev/null +++ b/.env.staging @@ -0,0 +1,16 @@ +# 棰勫彂甯冧篃闇�瑕佺敓浜х幆澧冪殑琛屼负 +# https://cn.vitejs.dev/guide/env-and-mode.html#modes +# NODE_ENV = development + +VITE_PUBLIC_PATH = / + +# 棰勫彂甯冪幆澧冭矾鐢卞巻鍙叉ā寮忥紙Hash妯″紡浼�"hash"銆丠TML5妯″紡浼�"h5"銆丠ash妯″紡甯ase鍙傛暟浼�"hash,base鍙傛暟"銆丠TML5妯″紡甯ase鍙傛暟浼�"h5,base鍙傛暟"锛� +VITE_ROUTER_HISTORY = "hash" + +# 鏄惁鍦ㄦ墦鍖呮椂浣跨敤cdn鏇挎崲鏈湴搴� 鏇挎崲 true 涓嶆浛鎹� false +VITE_CDN = true + +# 鏄惁鍚敤gzip鍘嬬缉鎴朾rotli鍘嬬缉锛堝垎涓ょ鎯呭喌锛屽垹闄ゅ師濮嬫枃浠跺拰涓嶅垹闄ゅ師濮嬫枃浠讹級 +# 鍘嬬缉鏃朵笉鍒犻櫎鍘熷鏂囦欢鐨勯厤缃細gzip銆乥rotli銆乥oth锛堝悓鏃跺紑鍚� gzip 涓� brotli 鍘嬬缉锛夈�乶one锛堜笉寮�鍚帇缂╋紝榛樿锛� +# 鍘嬬缉鏃跺垹闄ゅ師濮嬫枃浠剁殑閰嶇疆锛歡zip-clear銆乥rotli-clear銆乥oth-clear锛堝悓鏃跺紑鍚� gzip 涓� brotli 鍘嬬缉锛夈�乶one锛堜笉寮�鍚帇缂╋紝榛樿锛� +VITE_COMPRESSION = "none" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..423ed2b --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +node_modules +.DS_Store +dist +dist-ssr +*.local +.eslintcache +report.html +vite.config.*.timestamp* + +yarn.lock +npm-debug.log* +.pnpm-error.log* +.pnpm-debug.log +tests/**/coverage/ + +# Editor directories and files +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +tsconfig.tsbuildinfo \ No newline at end of file diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100644 index 0000000..5ee2d16 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,8 @@ +#!/bin/sh + +# shellcheck source=./_/husky.sh +. "$(dirname "$0")/_/husky.sh" + +PATH="/usr/local/bin:$PATH" + +npx --no-install commitlint --edit "$1" \ No newline at end of file diff --git a/.husky/common.sh b/.husky/common.sh new file mode 100644 index 0000000..5f0540b --- /dev/null +++ b/.husky/common.sh @@ -0,0 +1,9 @@ +#!/bin/sh +command_exists () { + command -v "$1" >/dev/null 2>&1 +} + +# Workaround for Windows 10, Git Bash and Pnpm +if command_exists winpty && test -t 1; then + exec < /dev/tty +fi diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..6e229ea --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,10 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" +. "$(dirname "$0")/common.sh" + +[ -n "$CI" ] && exit 0 + +PATH="/usr/local/bin:$PATH" + +# Perform lint check on files in the staging area through .lintstagedrc configuration +pnpm exec lint-staged \ No newline at end of file diff --git a/.lintstagedrc b/.lintstagedrc new file mode 100644 index 0000000..ebf359a --- /dev/null +++ b/.lintstagedrc @@ -0,0 +1,20 @@ +{ + "*.{js,jsx,ts,tsx}": [ + "prettier --cache --ignore-unknown --write", + "eslint --cache --fix" + ], + "{!(package)*.json,*.code-snippets,.!({browserslist,npm,nvm})*rc}": [ + "prettier --cache --write--parser json" + ], + "package.json": ["prettier --cache --write"], + "*.vue": [ + "prettier --write", + "eslint --cache --fix", + "stylelint --fix --allow-empty-input" + ], + "*.{css,scss,html}": [ + "prettier --cache --ignore-unknown --write", + "stylelint --fix --allow-empty-input" + ], + "*.md": ["prettier --cache --ignore-unknown --write"] +} diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..d628d44 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,11 @@ +{ + "default": true, + "MD003": false, + "MD033": false, + "MD013": false, + "MD001": false, + "MD025": false, + "MD024": false, + "MD007": { "indent": 4 }, + "no-hard-tabs": false +} diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..dddf8bc --- /dev/null +++ b/.npmrc @@ -0,0 +1,4 @@ +shell-emulator=true +shamefully-hoist=true +enable-pre-post-scripts=false +strict-peer-dependencies=false \ No newline at end of file diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..c5ddcef --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v22.14.0 \ No newline at end of file diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..775d970 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,9 @@ +// @ts-check + +/** @type {import("prettier").Config} */ +export default { + bracketSpacing: true, + singleQuote: false, + arrowParens: "avoid", + trailingComma: "none" +}; diff --git a/.stylelintignore b/.stylelintignore new file mode 100644 index 0000000..0c34e61 --- /dev/null +++ b/.stylelintignore @@ -0,0 +1,4 @@ +/dist/* +/public/* +public/* +src/style/reset.scss \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..b36b3f8 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,19 @@ +{ + "recommendations": [ + "christian-kohler.path-intellisense", + "warmthsea.vscode-custom-code-color", + "vscode-icons-team.vscode-icons", + "davidanson.vscode-markdownlint", + "ms-azuretools.vscode-docker", + "stylelint.vscode-stylelint", + "bradlc.vscode-tailwindcss", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "redhat.vscode-yaml", + "csstools.postcss", + "mikestead.dotenv", + "eamodio.gitlens", + "antfu.iconify", + "Vue.volar" + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..388b96f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,43 @@ +{ + "editor.formatOnType": true, + "editor.formatOnSave": true, + "[vue]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "editor.tabSize": 2, + "editor.formatOnPaste": true, + "editor.guides.bracketPairs": "active", + "files.autoSave": "afterDelay", + "git.confirmSync": false, + "workbench.startupEditor": "newUntitledFile", + "editor.suggestSelection": "first", + "editor.acceptSuggestionOnCommitCharacter": false, + "css.lint.propertyIgnoredDueToDisplay": "ignore", + "editor.quickSuggestions": { + "other": true, + "comments": true, + "strings": true + }, + "files.associations": { + "editor.snippetSuggestions": "top" + }, + "[css]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + "iconify.excludes": [ + "el" + ], + "vscodeCustomCodeColor.highlightValue": [ + "v-loading", + "v-auth", + "v-copy", + "v-longpress", + "v-optimize", + "v-perms", + "v-ripple" + ], + "vscodeCustomCodeColor.highlightValueColor": "#b392f0", +} \ No newline at end of file diff --git a/.vscode/vue3.0.code-snippets b/.vscode/vue3.0.code-snippets new file mode 100644 index 0000000..bb43589 --- /dev/null +++ b/.vscode/vue3.0.code-snippets @@ -0,0 +1,22 @@ +{ + "Vue3.0蹇�熺敓鎴愭ā鏉�": { + "scope": "vue", + "prefix": "Vue3.0", + "body": [ + "<template>", + "\t<div>test</div>", + "</template>\n", + "<script lang='ts'>", + "export default {", + "\tsetup() {", + "\t\treturn {}", + "\t}", + "}", + "</script>\n", + "<style lang='scss' scoped>\n", + "</style>", + "$2" + ], + "description": "Vue3.0" + } +} diff --git a/.vscode/vue3.2.code-snippets b/.vscode/vue3.2.code-snippets new file mode 100644 index 0000000..2cebb46 --- /dev/null +++ b/.vscode/vue3.2.code-snippets @@ -0,0 +1,17 @@ +{ + "Vue3.2+蹇�熺敓鎴愭ā鏉�": { + "scope": "vue", + "prefix": "Vue3.2+", + "body": [ + "<script setup lang='ts'>", + "</script>\n", + "<template>", + "\t<div>test</div>", + "</template>\n", + "<style lang='scss' scoped>\n", + "</style>", + "$2" + ], + "description": "Vue3.2+" + } +} diff --git a/.vscode/vue3.3.code-snippets b/.vscode/vue3.3.code-snippets new file mode 100644 index 0000000..dc7a106 --- /dev/null +++ b/.vscode/vue3.3.code-snippets @@ -0,0 +1,20 @@ +{ + "Vue3.3+defineOptions蹇�熺敓鎴愭ā鏉�": { + "scope": "vue", + "prefix": "Vue3.3+", + "body": [ + "<script setup lang='ts'>", + "defineOptions({", + "\tname: ''", + "})", + "</script>\n", + "<template>", + "\t<div>test</div>", + "</template>\n", + "<style lang='scss' scoped>\n", + "</style>", + "$2" + ], + "description": "Vue3.3+defineOptions蹇�熺敓鎴愭ā鏉�" + } +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..cd6d51a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +FROM node:20-alpine as build-stage + +WORKDIR /app +RUN corepack enable +RUN corepack prepare pnpm@latest --activate + +RUN npm config set registry https://registry.npmmirror.com + +COPY .npmrc package.json pnpm-lock.yaml ./ +RUN pnpm install --frozen-lockfile + +COPY . . +RUN pnpm build + +FROM nginx:stable-alpine as production-stage + +COPY --from=build-stage /app/dist /usr/share/nginx/html +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6d4889d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020-present, pure-admin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.en-US.md b/README.en-US.md new file mode 100644 index 0000000..104b8d5 --- /dev/null +++ b/README.en-US.md @@ -0,0 +1,39 @@ +<h1>vue-pure-admin Lite Edition锛坣o i18n version锛�</h1> + +[](LICENSE) + +**English** | [涓枃](./README.md) + +## Introduce + +The simplified version is based on the shelf extracted from [vue-pure-admin](https://github.com/pure-admin/vue-pure-admin), which contains main functions and is more suitable for actual project development. The packaged size is introduced globally [element-plus](https://element-plus.org) is still below `2.3MB`, and the full version of the code will be permanently synchronized. After enabling `brotli` compression and `cdn` to replace the local library mode, the package size is less than `350kb` + +## Supporting video + +[Click me to view UI design](https://www.bilibili.com/video/BV17g411T7rq) +[Click me to view the rapid development tutorial](https://www.bilibili.com/video/BV1kg411v7QT) + +## Nanny-level documents + +[Click me to view vue-pure-admin documentation](https://pure-admin.cn/) +[Click me to view @pureadmin/utils documentation](https://pure-admin-utils.netlify.app) + +## Premium service + +[Click me to view details](https://pure-admin.cn/pages/service/) + +## Preview + +[Click me to view the preview station](https://pure-admin-thin.netlify.app/#/login) + +## Maintainer + +[xiaoxian521](https://github.com/xiaoxian521) + +## 鈿狅笍 Attention + +The Lite version does not accept any issues and prs. If you have any questions, please go to the full version [issues](https://github.com/pure-admin/vue-pure-admin/issues/new/choose) to mention, thank you! + +## License + +[MIT 漏 2020-present, pure-admin](./LICENSE) diff --git a/build/cdn.ts b/build/cdn.ts new file mode 100644 index 0000000..c56e4ad --- /dev/null +++ b/build/cdn.ts @@ -0,0 +1,55 @@ +import { Plugin as importToCDN } from "vite-plugin-cdn-import"; + +/** + * @description 鎵撳寘鏃堕噰鐢╜cdn`妯″紡锛屼粎闄愬缃戜娇鐢紙榛樿涓嶉噰鐢紝濡傛灉闇�瑕侀噰鐢╟dn妯″紡锛岃鍦� .env.production 鏂囦欢锛屽皢 VITE_CDN 璁剧疆鎴恡rue锛� + * 骞冲彴閲囩敤鍥藉唴cdn锛歨ttps://www.bootcdn.cn锛屽綋鐒朵綘涔熷彲浠ラ�夋嫨 https://unpkg.com 鎴栬�� https://www.jsdelivr.com + * 娉ㄦ剰锛氫笂闈㈡彁鍒扮殑浠呴檺澶栫綉浣跨敤涔熶笉鏄畬鍏ㄨ偗瀹氱殑锛屽鏋滀綘浠叕鍙稿唴缃戦儴缃茬殑鏈夌浉鍏砵s銆乧ss鏂囦欢锛屼篃鍙互灏嗕笅闈㈤厤缃搴旀敼涓�涓嬶紝鏁翠竴濂楀唴缃戠増cdn + */ +export const cdn = importToCDN({ + //锛坧rodUrl瑙i噴锛� name: 瀵瑰簲涓嬮潰modules鐨刵ame锛寁ersion: 鑷姩璇诲彇鏈湴package.json涓璬ependencies渚濊禆涓搴斿寘鐨勭増鏈彿锛宲ath: 瀵瑰簲涓嬮潰modules鐨刾ath锛屽綋鐒朵篃鍙啓瀹屾暣璺緞锛屼細鏇挎崲prodUrl锛� + prodUrl: "https://cdn.bootcdn.net/ajax/libs/{name}/{version}/{path}", + modules: [ + { + name: "vue", + var: "Vue", + path: "vue.global.prod.min.js" + }, + { + name: "vue-router", + var: "VueRouter", + path: "vue-router.global.min.js" + }, + // 椤圭洰涓病鏈夌洿鎺ュ畨瑁卾ue-demi锛屼絾鏄痯inia鐢ㄥ埌浜嗭紝鎵�浠ラ渶瑕佸湪寮曞叆pinia鍓嶅紩鍏ue-demi锛坔ttps://github.com/vuejs/pinia/blob/v2/packages/pinia/package.json#L77锛� + { + name: "vue-demi", + var: "VueDemi", + path: "index.iife.min.js" + }, + { + name: "pinia", + var: "Pinia", + path: "pinia.iife.min.js" + }, + { + name: "element-plus", + var: "ElementPlus", + path: "index.full.min.js", + css: "index.min.css" + }, + { + name: "axios", + var: "axios", + path: "axios.min.js" + }, + { + name: "dayjs", + var: "dayjs", + path: "dayjs.min.js" + }, + { + name: "echarts", + var: "echarts", + path: "echarts.min.js" + } + ] +}); diff --git a/build/compress.ts b/build/compress.ts new file mode 100644 index 0000000..6178986 --- /dev/null +++ b/build/compress.ts @@ -0,0 +1,63 @@ +import type { Plugin } from "vite"; +import { isArray } from "@pureadmin/utils"; +import compressPlugin from "vite-plugin-compression"; + +export const configCompressPlugin = ( + compress: ViteCompression +): Plugin | Plugin[] => { + if (compress === "none") return null; + + const gz = { + // 鐢熸垚鐨勫帇缂╁寘鍚庣紑 + ext: ".gz", + // 浣撶Н澶т簬threshold鎵嶄細琚帇缂� + threshold: 0, + // 榛樿鍘嬬缉.js|mjs|json|css|html鍚庣紑鏂囦欢锛岃缃垚true锛屽帇缂╁叏閮ㄦ枃浠� + filter: () => true, + // 鍘嬬缉鍚庢槸鍚﹀垹闄ゅ師濮嬫枃浠� + deleteOriginFile: false + }; + const br = { + ext: ".br", + algorithm: "brotliCompress", + threshold: 0, + filter: () => true, + deleteOriginFile: false + }; + + const codeList = [ + { k: "gzip", v: gz }, + { k: "brotli", v: br }, + { k: "both", v: [gz, br] } + ]; + + const plugins: Plugin[] = []; + + codeList.forEach(item => { + if (compress.includes(item.k)) { + if (compress.includes("clear")) { + if (isArray(item.v)) { + item.v.forEach(vItem => { + plugins.push( + compressPlugin(Object.assign(vItem, { deleteOriginFile: true })) + ); + }); + } else { + plugins.push( + compressPlugin(Object.assign(item.v, { deleteOriginFile: true })) + ); + } + } else { + if (isArray(item.v)) { + item.v.forEach(vItem => { + plugins.push(compressPlugin(vItem)); + }); + } else { + plugins.push(compressPlugin(item.v)); + } + } + } + }); + + return plugins; +}; diff --git a/build/info.ts b/build/info.ts new file mode 100644 index 0000000..679dd88 --- /dev/null +++ b/build/info.ts @@ -0,0 +1,57 @@ +import type { Plugin } from "vite"; +import gradient from "gradient-string"; +import { getPackageSize } from "./utils"; +import dayjs, { type Dayjs } from "dayjs"; +import duration from "dayjs/plugin/duration"; +import boxen, { type Options as BoxenOptions } from "boxen"; +dayjs.extend(duration); + +const welcomeMessage = gradient(["cyan", "magenta"]).multiline( + `鎮ㄥソ! 娆㈣繋浣跨敤 pure-admin 寮�婧愰」鐩甛n鎴戜滑涓烘偍绮惧績鍑嗗浜嗕笅闈袱涓创蹇冪殑淇濆绾ф枃妗nhttps://pure-admin.cn\nhttps://pure-admin-utils.netlify.app` +); + +const boxenOptions: BoxenOptions = { + padding: 0.5, + borderColor: "cyan", + borderStyle: "round" +}; + +export function viteBuildInfo(): Plugin { + let config: { command: string }; + let startTime: Dayjs; + let endTime: Dayjs; + let outDir: string; + return { + name: "vite:buildInfo", + configResolved(resolvedConfig) { + config = resolvedConfig; + outDir = resolvedConfig.build?.outDir ?? "dist"; + }, + buildStart() { + console.log(boxen(welcomeMessage, boxenOptions)); + if (config.command === "build") { + startTime = dayjs(new Date()); + } + }, + closeBundle() { + if (config.command === "build") { + endTime = dayjs(new Date()); + getPackageSize({ + folder: outDir, + callback: (size: string) => { + console.log( + boxen( + gradient(["cyan", "magenta"]).multiline( + `馃帀 鎭枩鎵撳寘瀹屾垚锛堟�荤敤鏃�${dayjs + .duration(endTime.diff(startTime)) + .format("mm鍒唖s绉�")}锛屾墦鍖呭悗鐨勫ぇ灏忎负${size}锛塦 + ), + boxenOptions + ) + ); + } + }); + } + } + }; +} diff --git a/build/optimize.ts b/build/optimize.ts new file mode 100644 index 0000000..3fad18f --- /dev/null +++ b/build/optimize.ts @@ -0,0 +1,29 @@ +/** + * 姝ゆ枃浠朵綔鐢ㄤ簬 `vite.config.ts` 鐨� `optimizeDeps.include` 渚濊禆棰勬瀯寤洪厤缃」 + * 渚濊禆棰勬瀯寤猴紝`vite` 鍚姩鏃朵細灏嗕笅闈� include 閲岀殑妯″潡锛岀紪璇戞垚 esm 鏍煎紡骞剁紦瀛樺埌 node_modules/.vite 鏂囦欢澶癸紝椤甸潰鍔犺浇鍒板搴旀ā鍧楁椂濡傛灉娴忚鍣ㄦ湁缂撳瓨灏辫鍙栨祻瑙堝櫒缂撳瓨锛屽鏋滄病鏈変細璇诲彇鏈湴缂撳瓨骞舵寜闇�鍔犺浇 + * 灏ゅ叾褰撴偍绂佺敤娴忚鍣ㄧ紦瀛樻椂锛堣繖绉嶆儏鍐靛彧搴旇鍙戠敓鍦ㄨ皟璇曢樁娈碉級蹇呴』灏嗗搴旀ā鍧楀姞鍏ュ埌 include閲岋紝鍚﹀垯浼氶亣鍒板紑鍙戠幆澧冨垏鎹㈤〉闈㈠崱椤跨殑闂锛坴ite 浼氳涓哄畠鏄竴涓柊鐨勪緷璧栧寘浼氶噸鏂板姞杞藉苟寮哄埗鍒锋柊椤甸潰锛夛紝鍥犱负瀹冩棦鏃犳硶浣跨敤娴忚鍣ㄧ紦瀛橈紝鍙堟病鏈夊湪鏈湴 node_modules/.vite 閲岀紦瀛� + * 娓╅Θ鎻愮ず锛氬鏋滄偍浣跨敤鐨勭涓夋柟搴撴槸鍏ㄥ眬寮曞叆锛屼篃灏辨槸寮曞叆鍒� src/main.ts 鏂囦欢閲岋紝灏变笉闇�瑕佸啀娣诲姞鍒� include 閲屼簡锛屽洜涓� vite 浼氳嚜鍔ㄥ皢瀹冧滑缂撳瓨鍒� node_modules/.vite + */ +const include = [ + "qs", + "mitt", + "dayjs", + "axios", + "pinia", + "vue-types", + "js-cookie", + "vue-tippy", + "pinyin-pro", + "sortablejs", + "@vueuse/core", + "@pureadmin/utils", + "responsive-storage" +]; + +/** + * 鍦ㄩ鏋勫缓涓己鍒舵帓闄ょ殑渚濊禆椤� + * 娓╅Θ鎻愮ず锛氬钩鍙版帹鑽愮殑浣跨敤鏂瑰紡鏄摢閲岄渶瑕佸摢閲屽紩鍏ヨ�屼笖閮芥槸鍗曚釜鐨勫紩鍏ワ紝涓嶉渶瑕侀鏋勫缓锛岀洿鎺ヨ娴忚鍣ㄥ姞杞藉氨濂� + */ +const exclude = ["@iconify/json"]; + +export { include, exclude }; diff --git a/build/plugins.ts b/build/plugins.ts new file mode 100644 index 0000000..93f5981 --- /dev/null +++ b/build/plugins.ts @@ -0,0 +1,66 @@ +import { cdn } from "./cdn"; +import vue from "@vitejs/plugin-vue"; +import { viteBuildInfo } from "./info"; +import svgLoader from "vite-svg-loader"; +import Icons from "unplugin-icons/vite"; +import type { PluginOption } from "vite"; +import vueJsx from "@vitejs/plugin-vue-jsx"; +import tailwindcss from "@tailwindcss/vite"; +import { configCompressPlugin } from "./compress"; +import removeNoMatch from "vite-plugin-router-warn"; +import { visualizer } from "rollup-plugin-visualizer"; +import removeConsole from "vite-plugin-remove-console"; +import { codeInspectorPlugin } from "code-inspector-plugin"; +import { vitePluginFakeServer } from "vite-plugin-fake-server"; + +export function getPluginsList( + VITE_CDN: boolean, + VITE_COMPRESSION: ViteCompression +): PluginOption[] { + const lifecycle = process.env.npm_lifecycle_event; + return [ + tailwindcss(), + vue(), + // jsx銆乼sx璇硶鏀寔 + vueJsx(), + /** + * 鍦ㄩ〉闈笂鎸変綇缁勫悎閿椂锛岄紶鏍囧湪椤甸潰绉诲姩鍗充細鍦� DOM 涓婂嚭鐜伴伄缃╁眰骞舵樉绀虹浉鍏充俊鎭紝鐐瑰嚮涓�涓嬪皢鑷姩鎵撳紑 IDE 骞跺皢鍏夋爣瀹氫綅鍒板厓绱犲搴旂殑浠g爜浣嶇疆 + * Mac 榛樿缁勫悎閿� Option + Shift + * Windows 榛樿缁勫悎閿� Alt + Shift + * 鏇村鐢ㄦ硶鐪� https://inspector.fe-dev.cn/guide/start.html + */ + codeInspectorPlugin({ + bundler: "vite", + hideConsole: true + }), + viteBuildInfo(), + /** + * 寮�鍙戠幆澧冧笅绉婚櫎闈炲繀瑕佺殑vue-router鍔ㄦ�佽矾鐢辫鍛奛o match found for location with path + * 闈炲繀瑕佸叿浣撶湅 https://github.com/vuejs/router/issues/521 鍜� https://github.com/vuejs/router/issues/359 + * vite-plugin-router-warn鍙湪寮�鍙戠幆澧冧笅鍚敤锛屽彧澶勭悊vue-router鏂囦欢骞朵笖鍙湪鏈嶅姟鍚姩鎴栭噸鍚椂杩愯涓�娆★紝鎬ц兘娑堣�楀彲蹇界暐涓嶈 + */ + removeNoMatch(), + // mock鏀寔 + vitePluginFakeServer({ + logger: false, + include: "mock", + infixName: false, + enableProd: true + }), + // svg缁勪欢鍖栨敮鎸� + svgLoader(), + // 鑷姩鎸夐渶鍔犺浇鍥炬爣 + Icons({ + compiler: "vue3", + scale: 1 + }), + VITE_CDN ? cdn : null, + configCompressPlugin(VITE_COMPRESSION), + // 绾夸笂鐜鍒犻櫎console + removeConsole({ external: ["src/assets/iconfont/iconfont.js"] }), + // 鎵撳寘鍒嗘瀽 + lifecycle === "report" + ? visualizer({ open: true, brotliSize: true, filename: "report.html" }) + : (null as any) + ]; +} diff --git a/build/utils.ts b/build/utils.ts new file mode 100644 index 0000000..3d778fe --- /dev/null +++ b/build/utils.ts @@ -0,0 +1,110 @@ +import dayjs from "dayjs"; +import { readdir, stat } from "node:fs"; +import { fileURLToPath } from "node:url"; +import { dirname, resolve } from "node:path"; +import { sum, formatBytes } from "@pureadmin/utils"; +import { + name, + version, + engines, + dependencies, + devDependencies +} from "../package.json"; + +/** 鍚姩`node`杩涚▼鏃舵墍鍦ㄥ伐浣滅洰褰曠殑缁濆璺緞 */ +const root: string = process.cwd(); + +/** + * @description 鏍规嵁鍙�夌殑璺緞鐗囨鐢熸垚涓�涓柊鐨勭粷瀵硅矾寰� + * @param dir 璺緞鐗囨锛岄粯璁build` + * @param metaUrl 妯″潡鐨勫畬鏁碻url`锛屽鏋滃湪`build`鐩綍澶栬皟鐢ㄥ繀浼燻import.meta.url` + */ +const pathResolve = (dir = ".", metaUrl = import.meta.url) => { + // 褰撳墠鏂囦欢鐩綍鐨勭粷瀵硅矾寰� + const currentFileDir = dirname(fileURLToPath(metaUrl)); + // build 鐩綍鐨勭粷瀵硅矾寰� + const buildDir = resolve(currentFileDir, "build"); + // 瑙f瀽鐨勭粷瀵硅矾寰� + const resolvedPath = resolve(currentFileDir, dir); + // 妫�鏌ヨВ鏋愮殑缁濆璺緞鏄惁鍦� build 鐩綍鍐� + if (resolvedPath.startsWith(buildDir)) { + // 鍦� build 鐩綍鍐咃紝杩斿洖褰撳墠鏂囦欢璺緞 + return fileURLToPath(metaUrl); + } + // 涓嶅湪 build 鐩綍鍐咃紝杩斿洖瑙f瀽鍚庣殑缁濆璺緞 + return resolvedPath; +}; + +/** 璁剧疆鍒悕 */ +const alias: Record<string, string> = { + "@": pathResolve("../src"), + "@build": pathResolve() +}; + +/** 骞冲彴鐨勫悕绉般�佺増鏈�佽繍琛屾墍闇�鐨刞node`鍜宍pnpm`鐗堟湰銆佷緷璧栥�佹渶鍚庢瀯寤烘椂闂寸殑绫诲瀷鎻愮ず */ +const __APP_INFO__ = { + pkg: { name, version, engines, dependencies, devDependencies }, + lastBuildTime: dayjs(new Date()).format("YYYY-MM-DD HH:mm:ss") +}; + +/** 澶勭悊鐜鍙橀噺 */ +const wrapperEnv = (envConf: Recordable): ViteEnv => { + // 榛樿鍊� + const ret: ViteEnv = { + VITE_PORT: 8848, + VITE_PUBLIC_PATH: "", + VITE_ROUTER_HISTORY: "", + VITE_CDN: false, + VITE_HIDE_HOME: "false", + VITE_COMPRESSION: "none" + }; + + for (const envName of Object.keys(envConf)) { + let realName = envConf[envName].replace(/\\n/g, "\n"); + realName = + realName === "true" ? true : realName === "false" ? false : realName; + + if (envName === "VITE_PORT") { + realName = Number(realName); + } + ret[envName] = realName; + if (typeof realName === "string") { + process.env[envName] = realName; + } else if (typeof realName === "object") { + process.env[envName] = JSON.stringify(realName); + } + } + return ret; +}; + +const fileListTotal: number[] = []; + +/** 鑾峰彇鎸囧畾鏂囦欢澶逛腑鎵�鏈夋枃浠剁殑鎬诲ぇ灏� */ +const getPackageSize = options => { + const { folder = "dist", callback, format = true } = options; + readdir(folder, (err, files: string[]) => { + if (err) throw err; + let count = 0; + const checkEnd = () => { + ++count == files.length && + callback(format ? formatBytes(sum(fileListTotal)) : sum(fileListTotal)); + }; + files.forEach((item: string) => { + stat(`${folder}/${item}`, async (err, stats) => { + if (err) throw err; + if (stats.isFile()) { + fileListTotal.push(stats.size); + checkEnd(); + } else if (stats.isDirectory()) { + getPackageSize({ + folder: `${folder}/${item}/`, + callback: checkEnd + }); + } + }); + }); + files.length === 0 && callback(0); + }); +}; + +export { root, pathResolve, alias, __APP_INFO__, wrapperEnv, getPackageSize }; diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 0000000..eea755d --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,35 @@ +// @ts-check + +/** @type {import("@commitlint/types").UserConfig} */ +export default { + ignores: [commit => commit.includes("init")], + extends: ["@commitlint/config-conventional"], + rules: { + "body-leading-blank": [2, "always"], + "footer-leading-blank": [1, "always"], + "header-max-length": [2, "always", 108], + "subject-empty": [2, "never"], + "type-empty": [2, "never"], + "type-enum": [ + 2, + "always", + [ + "feat", + "fix", + "perf", + "style", + "docs", + "test", + "refactor", + "build", + "ci", + "chore", + "revert", + "wip", + "workflow", + "types", + "release" + ] + ] + } +}; diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..a5be0cd --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,173 @@ +import js from "@eslint/js"; +import tseslint from "typescript-eslint"; +import pluginVue from "eslint-plugin-vue"; +import * as parserVue from "vue-eslint-parser"; +import configPrettier from "eslint-config-prettier"; +import pluginPrettier from "eslint-plugin-prettier"; +import { defineConfig, globalIgnores } from "eslint/config"; + +export default defineConfig([ + globalIgnores([ + "**/.*", + "dist/*", + "*.d.ts", + "public/*", + "src/assets/**", + "src/**/iconfont/**" + ]), + { + ...js.configs.recommended, + languageOptions: { + globals: { + // types/index.d.ts + RefType: "readonly", + EmitType: "readonly", + TargetContext: "readonly", + ComponentRef: "readonly", + ElRef: "readonly", + ForDataType: "readonly", + AnyFunction: "readonly", + PropType: "readonly", + Writable: "readonly", + Nullable: "readonly", + NonNullable: "readonly", + Recordable: "readonly", + ReadonlyRecordable: "readonly", + Indexable: "readonly", + DeepPartial: "readonly", + Without: "readonly", + Exclusive: "readonly", + TimeoutHandle: "readonly", + IntervalHandle: "readonly", + Effect: "readonly", + ChangeEvent: "readonly", + WheelEvent: "readonly", + ImportMetaEnv: "readonly", + Fn: "readonly", + PromiseFn: "readonly", + ComponentElRef: "readonly", + parseInt: "readonly", + parseFloat: "readonly" + } + }, + plugins: { + prettier: pluginPrettier + }, + rules: { + ...configPrettier.rules, + ...pluginPrettier.configs.recommended.rules, + "no-debugger": "off", + "no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_" + } + ], + "prettier/prettier": [ + "error", + { + endOfLine: "auto" + } + ] + } + }, + ...tseslint.config({ + extends: [...tseslint.configs.recommended], + files: ["**/*.?([cm])ts", "**/*.?([cm])tsx"], + rules: { + "@typescript-eslint/no-redeclare": "error", + "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/prefer-as-const": "warn", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/no-unused-expressions": "off", + "@typescript-eslint/no-unsafe-function-type": "off", + "@typescript-eslint/no-import-type-side-effects": "error", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/consistent-type-imports": [ + "error", + { disallowTypeAnnotations: false, fixStyle: "inline-type-imports" } + ], + "@typescript-eslint/prefer-literal-enum-member": [ + "error", + { allowBitwiseExpressions: true } + ], + "@typescript-eslint/no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_" + } + ] + } + }), + { + files: ["**/*.d.ts"], + rules: { + "eslint-comments/no-unlimited-disable": "off", + "import/no-duplicates": "off", + "no-restricted-syntax": "off", + "unused-imports/no-unused-vars": "off" + } + }, + { + files: ["**/*.?([cm])js"], + rules: { + "@typescript-eslint/no-require-imports": "off" + } + }, + { + files: ["**/*.vue"], + languageOptions: { + globals: { + $: "readonly", + $$: "readonly", + $computed: "readonly", + $customRef: "readonly", + $ref: "readonly", + $shallowRef: "readonly", + $toRef: "readonly" + }, + parser: parserVue, + parserOptions: { + ecmaFeatures: { + jsx: true + }, + extraFileExtensions: [".vue"], + parser: tseslint.parser, + sourceType: "module" + } + }, + plugins: { + "@typescript-eslint": tseslint.plugin, + vue: pluginVue + }, + processor: pluginVue.processors[".vue"], + rules: { + ...pluginVue.configs.base.rules, + ...pluginVue.configs.essential.rules, + ...pluginVue.configs.recommended.rules, + "no-undef": "off", + "no-unused-vars": "off", + "vue/no-v-html": "off", + "vue/require-default-prop": "off", + "vue/require-explicit-emits": "off", + "vue/multi-word-component-names": "off", + "vue/no-setup-props-reactivity-loss": "off", + "vue/html-self-closing": [ + "error", + { + html: { + void: "always", + normal: "always", + component: "always" + }, + svg: "always", + math: "always" + } + ] + } + } +]); diff --git a/index.html b/index.html new file mode 100644 index 0000000..1193eef --- /dev/null +++ b/index.html @@ -0,0 +1,84 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> + <meta name="renderer" content="webkit" /> + <meta + name="viewport" + content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0" + /> + <title>pure-admin-thin</title> + <link rel="icon" href="/favicon.ico" /> + </head> + + <body> + <div id="app"> + <style> + html, + body, + #app { + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + overflow: hidden; + } + + .loader, + .loader::before, + .loader::after { + width: 2.5em; + height: 2.5em; + border-radius: 50%; + animation: load-animation 1.8s infinite ease-in-out; + animation-fill-mode: both; + } + + .loader { + position: relative; + top: 0; + margin: 80px auto; + font-size: 10px; + color: #406eeb; + text-indent: -9999em; + transform: translateZ(0); + transform: translate(-50%, 0); + animation-delay: -0.16s; + } + + .loader::before, + .loader::after { + position: absolute; + top: 0; + content: ""; + } + + .loader::before { + left: -3.5em; + animation-delay: -0.32s; + } + + .loader::after { + left: 3.5em; + } + + @keyframes load-animation { + 0%, + 80%, + 100% { + box-shadow: 0 2.5em 0 -1.3em; + } + + 40% { + box-shadow: 0 2.5em 0 0; + } + } + </style> + <div class="loader"></div> + </div> + <script type="module" src="/src/main.ts"></script> + </body> +</html> diff --git a/mock/asyncRoutes.ts b/mock/asyncRoutes.ts new file mode 100644 index 0000000..2a99183 --- /dev/null +++ b/mock/asyncRoutes.ts @@ -0,0 +1,69 @@ +// 妯℃嫙鍚庣鍔ㄦ�佺敓鎴愯矾鐢� +import { defineFakeRoute } from "vite-plugin-fake-server/client"; + +/** + * roles锛氶〉闈㈢骇鍒潈闄愶紝杩欓噷妯℃嫙浜岀 "admin"銆�"common" + * admin锛氱鐞嗗憳瑙掕壊 + * common锛氭櫘閫氳鑹� + */ +const permissionRouter = { + path: "/permission", + meta: { + title: "鏉冮檺绠$悊", + icon: "ep:lollipop", + rank: 10 + }, + children: [ + { + path: "/permission/page/index", + name: "PermissionPage", + meta: { + title: "椤甸潰鏉冮檺", + roles: ["admin", "common"] + } + }, + { + path: "/permission/button", + meta: { + title: "鎸夐挳鏉冮檺", + roles: ["admin", "common"] + }, + children: [ + { + path: "/permission/button/router", + component: "permission/button/index", + name: "PermissionButtonRouter", + meta: { + title: "璺敱杩斿洖鎸夐挳鏉冮檺", + auths: [ + "permission:btn:add", + "permission:btn:edit", + "permission:btn:delete" + ] + } + }, + { + path: "/permission/button/login", + component: "permission/button/perms", + name: "PermissionButtonLogin", + meta: { + title: "鐧诲綍鎺ュ彛杩斿洖鎸夐挳鏉冮檺" + } + } + ] + } + ] +}; + +export default defineFakeRoute([ + { + url: "/get-async-routes", + method: "get", + response: () => { + return { + success: true, + data: [permissionRouter] + }; + } + } +]); diff --git a/mock/login.ts b/mock/login.ts new file mode 100644 index 0000000..55897d8 --- /dev/null +++ b/mock/login.ts @@ -0,0 +1,42 @@ +// 鏍规嵁瑙掕壊鍔ㄦ�佺敓鎴愯矾鐢� +import { defineFakeRoute } from "vite-plugin-fake-server/client"; + +export default defineFakeRoute([ + { + url: "/login", + method: "post", + response: ({ body }) => { + if (body.username === "admin") { + return { + success: true, + data: { + avatar: "https://avatars.githubusercontent.com/u/44761321", + username: "admin", + nickname: "灏忛摥", + // 涓�涓敤鎴峰彲鑳芥湁澶氫釜瑙掕壊 + roles: ["admin"], + // 鎸夐挳绾у埆鏉冮檺 + permissions: ["*:*:*"], + accessToken: "eyJhbGciOiJIUzUxMiJ9.admin", + refreshToken: "eyJhbGciOiJIUzUxMiJ9.adminRefresh", + expires: "2030/10/30 00:00:00" + } + }; + } else { + return { + success: true, + data: { + avatar: "https://avatars.githubusercontent.com/u/52823142", + username: "common", + nickname: "灏忔灄", + roles: ["common"], + permissions: ["permission:btn:add", "permission:btn:edit"], + accessToken: "eyJhbGciOiJIUzUxMiJ9.common", + refreshToken: "eyJhbGciOiJIUzUxMiJ9.commonRefresh", + expires: "2030/10/30 00:00:00" + } + }; + } + } + } +]); diff --git a/mock/refreshToken.ts b/mock/refreshToken.ts new file mode 100644 index 0000000..34d0e87 --- /dev/null +++ b/mock/refreshToken.ts @@ -0,0 +1,27 @@ +import { defineFakeRoute } from "vite-plugin-fake-server/client"; + +// 妯℃嫙鍒锋柊token鎺ュ彛 +export default defineFakeRoute([ + { + url: "/refresh-token", + method: "post", + response: ({ body }) => { + if (body.refreshToken) { + return { + success: true, + data: { + accessToken: "eyJhbGciOiJIUzUxMiJ9.newAdmin", + refreshToken: "eyJhbGciOiJIUzUxMiJ9.newAdminRefresh", + // `expires`閫夋嫨杩欑鏃ユ湡鏍煎紡鏄负浜嗘柟渚胯皟璇曪紝鍚庣鐩存帴璁剧疆鏃堕棿鎴虫垨璁告洿鏂逛究锛堟瘡娆¢兘搴旇閫掑锛夈�傚鏋滃悗绔繑鍥炵殑鏄椂闂存埑鏍煎紡锛屽墠绔紑鍙戣鏉ュ埌杩欎釜鐩綍`src/utils/auth.ts`锛屾妸绗琡38`琛岀殑浠g爜鎹㈡垚expires = data.expires鍗冲彲銆� + expires: "2030/10/30 23:59:59" + } + }; + } else { + return { + success: false, + data: {} + }; + } + } + } +]); diff --git a/package.json b/package.json new file mode 100644 index 0000000..484a473 --- /dev/null +++ b/package.json @@ -0,0 +1,159 @@ +{ + "name": "pure-admin-thin", + "version": "6.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "NODE_OPTIONS=--max-old-space-size=4096 vite", + "serve": "pnpm dev", + "build": "rimraf dist && NODE_OPTIONS=--max-old-space-size=8192 vite build", + "build:staging": "rimraf dist && vite build --mode staging", + "report": "rimraf dist && vite build", + "preview": "vite preview", + "preview:build": "pnpm build && vite preview", + "typecheck": "tsc --noEmit && vue-tsc --noEmit --skipLibCheck", + "svgo": "svgo -f . -r", + "clean:cache": "rimraf .eslintcache && rimraf pnpm-lock.yaml && rimraf node_modules && pnpm store prune && pnpm install", + "lint:eslint": "eslint --cache --max-warnings 0 \"{src,mock,build}/**/*.{vue,js,ts,tsx}\" --fix", + "lint:prettier": "prettier --write \"src/**/*.{js,ts,json,tsx,css,scss,vue,html,md}\"", + "lint:stylelint": "stylelint --cache --fix \"**/*.{html,vue,css,scss}\" --cache-location node_modules/.cache/stylelint/", + "lint": "pnpm lint:eslint && pnpm lint:prettier && pnpm lint:stylelint", + "prepare": "husky", + "preinstall": "npx only-allow pnpm" + }, + "keywords": [ + "pure-admin-thin", + "vue-pure-admin", + "element-plus", + "tailwindcss", + "pure-admin", + "typescript", + "pinia", + "vue3", + "vite", + "esm" + ], + "homepage": "https://github.com/pure-admin/pure-admin-thin", + "repository": { + "type": "git", + "url": "git+https://github.com/pure-admin/pure-admin-thin.git" + }, + "bugs": { + "url": "https://github.com/pure-admin/vue-pure-admin/issues" + }, + "license": "MIT", + "author": { + "name": "xiaoxian521", + "email": "pureadmin@163.com", + "url": "https://github.com/xiaoxian521" + }, + "dependencies": { + "@pureadmin/descriptions": "^1.2.1", + "@pureadmin/table": "^3.2.1", + "@pureadmin/utils": "^2.6.0", + "@vueuse/core": "^13.1.0", + "@vueuse/motion": "^3.0.3", + "animate.css": "^4.1.1", + "axios": "^1.9.0", + "dayjs": "^1.11.13", + "echarts": "^5.6.0", + "element-plus": "^2.9.8", + "js-cookie": "^3.0.5", + "localforage": "^1.10.0", + "mitt": "^3.0.1", + "nprogress": "^0.2.0", + "path-browserify": "^1.0.1", + "pinia": "^3.0.2", + "pinyin-pro": "^3.26.0", + "qs": "^6.14.0", + "responsive-storage": "^2.2.0", + "sortablejs": "^1.15.6", + "vue": "^3.5.13", + "vue-router": "^4.5.0", + "vue-tippy": "^6.7.0", + "vue-types": "^6.0.0" + }, + "devDependencies": { + "@commitlint/cli": "^19.8.0", + "@commitlint/config-conventional": "^19.8.0", + "@commitlint/types": "^19.8.0", + "@eslint/js": "^9.25.1", + "@faker-js/faker": "^9.7.0", + "@iconify/json": "^2.2.331", + "@iconify/vue": "4.2.0", + "@tailwindcss/vite": "^4.1.4", + "@types/js-cookie": "^3.0.6", + "@types/node": "^20.17.30", + "@types/nprogress": "^0.2.3", + "@types/path-browserify": "^1.0.3", + "@types/qs": "^6.9.18", + "@types/sortablejs": "^1.15.8", + "@vitejs/plugin-vue": "^5.2.3", + "@vitejs/plugin-vue-jsx": "^4.1.2", + "boxen": "^8.0.1", + "code-inspector-plugin": "^0.20.10", + "cssnano": "^7.0.6", + "eslint": "^9.25.1", + "eslint-config-prettier": "^10.1.2", + "eslint-plugin-prettier": "^5.2.6", + "eslint-plugin-vue": "^10.0.0", + "gradient-string": "^3.0.0", + "husky": "^9.1.7", + "lint-staged": "^15.5.1", + "postcss": "^8.5.3", + "postcss-html": "^1.8.0", + "postcss-load-config": "^6.0.1", + "postcss-scss": "^4.0.9", + "prettier": "^3.5.3", + "rimraf": "^6.0.1", + "rollup-plugin-visualizer": "^5.14.0", + "sass": "^1.87.0", + "stylelint": "^16.19.0", + "stylelint-config-recess-order": "^6.0.0", + "stylelint-config-recommended-vue": "^1.6.0", + "stylelint-config-standard-scss": "^14.0.0", + "stylelint-prettier": "^5.0.3", + "svgo": "^3.3.2", + "tailwindcss": "^4.1.4", + "typescript": "^5.8.3", + "typescript-eslint": "^8.31.0", + "unplugin-icons": "^22.1.0", + "vite": "^6.3.3", + "vite-plugin-cdn-import": "^1.0.1", + "vite-plugin-compression": "^0.5.1", + "vite-plugin-fake-server": "^2.2.0", + "vite-plugin-remove-console": "^2.2.0", + "vite-plugin-router-warn": "^1.0.0", + "vite-svg-loader": "^5.1.0", + "vue-eslint-parser": "^10.1.3", + "vue-tsc": "^2.2.10" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=22.0.0", + "pnpm": ">=9" + }, + "pnpm": { + "allowedDeprecatedVersions": { + "are-we-there-yet": "*", + "sourcemap-codec": "*", + "lodash.isequal": "*", + "domexception": "*", + "w3c-hr-time": "*", + "inflight": "*", + "npmlog": "*", + "rimraf": "*", + "stable": "*", + "gauge": "*", + "abab": "*", + "glob": "*" + }, + "onlyBuiltDependencies": [ + "@parcel/watcher", + "core-js", + "es5-ext", + "esbuild", + "typeit", + "vue-demi" + ] + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..b349195 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,7329 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@pureadmin/descriptions': + specifier: ^1.2.1 + version: 1.2.1(echarts@5.6.0)(element-plus@2.9.8(vue@3.5.13(typescript@5.8.3)))(typescript@5.8.3) + '@pureadmin/table': + specifier: ^3.2.1 + version: 3.2.1(element-plus@2.9.8(vue@3.5.13(typescript@5.8.3)))(typescript@5.8.3) + '@pureadmin/utils': + specifier: ^2.6.0 + version: 2.6.0(echarts@5.6.0)(vue@3.5.13(typescript@5.8.3)) + '@vueuse/core': + specifier: ^13.1.0 + version: 13.1.0(vue@3.5.13(typescript@5.8.3)) + '@vueuse/motion': + specifier: ^3.0.3 + version: 3.0.3(vue@3.5.13(typescript@5.8.3)) + animate.css: + specifier: ^4.1.1 + version: 4.1.1 + axios: + specifier: ^1.9.0 + version: 1.9.0 + dayjs: + specifier: ^1.11.13 + version: 1.11.13 + echarts: + specifier: ^5.6.0 + version: 5.6.0 + element-plus: + specifier: ^2.9.8 + version: 2.9.8(vue@3.5.13(typescript@5.8.3)) + js-cookie: + specifier: ^3.0.5 + version: 3.0.5 + localforage: + specifier: ^1.10.0 + version: 1.10.0 + mitt: + specifier: ^3.0.1 + version: 3.0.1 + nprogress: + specifier: ^0.2.0 + version: 0.2.0 + path-browserify: + specifier: ^1.0.1 + version: 1.0.1 + pinia: + specifier: ^3.0.2 + version: 3.0.2(typescript@5.8.3)(vue@3.5.13(typescript@5.8.3)) + pinyin-pro: + specifier: ^3.26.0 + version: 3.26.0 + qs: + specifier: ^6.14.0 + version: 6.14.0 + responsive-storage: + specifier: ^2.2.0 + version: 2.2.0 + sortablejs: + specifier: ^1.15.6 + version: 1.15.6 + vue: + specifier: ^3.5.13 + version: 3.5.13(typescript@5.8.3) + vue-router: + specifier: ^4.5.0 + version: 4.5.0(vue@3.5.13(typescript@5.8.3)) + vue-tippy: + specifier: ^6.7.0 + version: 6.7.0(vue@3.5.13(typescript@5.8.3)) + vue-types: + specifier: ^6.0.0 + version: 6.0.0(vue@3.5.13(typescript@5.8.3)) + devDependencies: + '@commitlint/cli': + specifier: ^19.8.0 + version: 19.8.0(@types/node@20.17.30)(typescript@5.8.3) + '@commitlint/config-conventional': + specifier: ^19.8.0 + version: 19.8.0 + '@commitlint/types': + specifier: ^19.8.0 + version: 19.8.0 + '@eslint/js': + specifier: ^9.25.1 + version: 9.25.1 + '@faker-js/faker': + specifier: ^9.7.0 + version: 9.7.0 + '@iconify/json': + specifier: ^2.2.331 + version: 2.2.331 + '@iconify/vue': + specifier: 4.2.0 + version: 4.2.0(vue@3.5.13(typescript@5.8.3)) + '@tailwindcss/vite': + specifier: ^4.1.4 + version: 4.1.4(vite@6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1)) + '@types/js-cookie': + specifier: ^3.0.6 + version: 3.0.6 + '@types/node': + specifier: ^20.17.30 + version: 20.17.30 + '@types/nprogress': + specifier: ^0.2.3 + version: 0.2.3 + '@types/path-browserify': + specifier: ^1.0.3 + version: 1.0.3 + '@types/qs': + specifier: ^6.9.18 + version: 6.9.18 + '@types/sortablejs': + specifier: ^1.15.8 + version: 1.15.8 + '@vitejs/plugin-vue': + specifier: ^5.2.3 + version: 5.2.3(vite@6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1))(vue@3.5.13(typescript@5.8.3)) + '@vitejs/plugin-vue-jsx': + specifier: ^4.1.2 + version: 4.1.2(vite@6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1))(vue@3.5.13(typescript@5.8.3)) + boxen: + specifier: ^8.0.1 + version: 8.0.1 + code-inspector-plugin: + specifier: ^0.20.10 + version: 0.20.10 + cssnano: + specifier: ^7.0.6 + version: 7.0.6(postcss@8.5.3) + eslint: + specifier: ^9.25.1 + version: 9.25.1(jiti@2.4.2) + eslint-config-prettier: + specifier: ^10.1.2 + version: 10.1.2(eslint@9.25.1(jiti@2.4.2)) + eslint-plugin-prettier: + specifier: ^5.2.6 + version: 5.2.6(eslint-config-prettier@10.1.2(eslint@9.25.1(jiti@2.4.2)))(eslint@9.25.1(jiti@2.4.2))(prettier@3.5.3) + eslint-plugin-vue: + specifier: ^10.0.0 + version: 10.0.0(eslint@9.25.1(jiti@2.4.2))(vue-eslint-parser@10.1.3(eslint@9.25.1(jiti@2.4.2))) + gradient-string: + specifier: ^3.0.0 + version: 3.0.0 + husky: + specifier: ^9.1.7 + version: 9.1.7 + lint-staged: + specifier: ^15.5.1 + version: 15.5.1 + postcss: + specifier: ^8.5.3 + version: 8.5.3 + postcss-html: + specifier: ^1.8.0 + version: 1.8.0 + postcss-load-config: + specifier: ^6.0.1 + version: 6.0.1(jiti@2.4.2)(postcss@8.5.3)(yaml@2.7.1) + postcss-scss: + specifier: ^4.0.9 + version: 4.0.9(postcss@8.5.3) + prettier: + specifier: ^3.5.3 + version: 3.5.3 + rimraf: + specifier: ^6.0.1 + version: 6.0.1 + rollup-plugin-visualizer: + specifier: ^5.14.0 + version: 5.14.0(rollup@4.40.0) + sass: + specifier: ^1.87.0 + version: 1.87.0 + stylelint: + specifier: ^16.19.0 + version: 16.19.0(typescript@5.8.3) + stylelint-config-recess-order: + specifier: ^6.0.0 + version: 6.0.0(stylelint@16.19.0(typescript@5.8.3)) + stylelint-config-recommended-vue: + specifier: ^1.6.0 + version: 1.6.0(postcss-html@1.8.0)(stylelint@16.19.0(typescript@5.8.3)) + stylelint-config-standard-scss: + specifier: ^14.0.0 + version: 14.0.0(postcss@8.5.3)(stylelint@16.19.0(typescript@5.8.3)) + stylelint-prettier: + specifier: ^5.0.3 + version: 5.0.3(prettier@3.5.3)(stylelint@16.19.0(typescript@5.8.3)) + svgo: + specifier: ^3.3.2 + version: 3.3.2 + tailwindcss: + specifier: ^4.1.4 + version: 4.1.4 + typescript: + specifier: ^5.8.3 + version: 5.8.3 + typescript-eslint: + specifier: ^8.31.0 + version: 8.31.0(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3) + unplugin-icons: + specifier: ^22.1.0 + version: 22.1.0(@vue/compiler-sfc@3.5.13) + vite: + specifier: ^6.3.3 + version: 6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1) + vite-plugin-cdn-import: + specifier: ^1.0.1 + version: 1.0.1(rollup@4.40.0)(vite@6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1)) + vite-plugin-compression: + specifier: ^0.5.1 + version: 0.5.1(vite@6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1)) + vite-plugin-fake-server: + specifier: ^2.2.0 + version: 2.2.0 + vite-plugin-remove-console: + specifier: ^2.2.0 + version: 2.2.0 + vite-plugin-router-warn: + specifier: ^1.0.0 + version: 1.0.0 + vite-svg-loader: + specifier: ^5.1.0 + version: 5.1.0(vue@3.5.13(typescript@5.8.3)) + vue-eslint-parser: + specifier: ^10.1.3 + version: 10.1.3(eslint@9.25.1(jiti@2.4.2)) + vue-tsc: + specifier: ^2.2.10 + version: 2.2.10(typescript@5.8.3) + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@antfu/install-pkg@1.0.0': + resolution: {integrity: sha512-xvX6P/lo1B3ej0OsaErAjqgFYzYVcJpamjLAFLYh9vRJngBrMoUG7aVnrGTeqM7yxbyTD5p3F2+0/QUEh8Vzhw==} + + '@antfu/utils@8.1.1': + resolution: {integrity: sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==} + + '@babel/code-frame@7.26.2': + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.26.8': + resolution: {integrity: sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.26.10': + resolution: {integrity: sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.27.0': + resolution: {integrity: sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.25.9': + resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.27.0': + resolution: {integrity: sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-create-class-features-plugin@7.27.0': + resolution: {integrity: sha512-vSGCvMecvFCd/BdpGlhpXYNhhC4ccxyvQWpbGL4CWbvfEoLFWUZuSuf7s9Aw70flgQF+6vptvgK2IfOnKlRmBg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-member-expression-to-functions@7.25.9': + resolution: {integrity: sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.25.9': + resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.26.0': + resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.25.9': + resolution: {integrity: sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.26.5': + resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-replace-supers@7.26.5': + resolution: {integrity: sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.25.9': + resolution: {integrity: sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.25.9': + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.25.9': + resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.27.0': + resolution: {integrity: sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.27.0': + resolution: {integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-jsx@7.25.9': + resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.25.9': + resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typescript@7.27.0': + resolution: {integrity: sha512-fRGGjO2UEGPjvEcyAZXRXAS8AfdaQoq7HnxAbJoAoW10B9xOKesmmndJv+Sym2a+9FHWZ9KbyyLCe9s0Sn5jtg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.27.0': + resolution: {integrity: sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.27.0': + resolution: {integrity: sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.27.0': + resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==} + engines: {node: '>=6.9.0'} + + '@commitlint/cli@19.8.0': + resolution: {integrity: sha512-t/fCrLVu+Ru01h0DtlgHZXbHV2Y8gKocTR5elDOqIRUzQd0/6hpt2VIWOj9b3NDo7y4/gfxeR2zRtXq/qO6iUg==} + engines: {node: '>=v18'} + hasBin: true + + '@commitlint/config-conventional@19.8.0': + resolution: {integrity: sha512-9I2kKJwcAPwMoAj38hwqFXG0CzS2Kj+SAByPUQ0SlHTfb7VUhYVmo7G2w2tBrqmOf7PFd6MpZ/a1GQJo8na8kw==} + engines: {node: '>=v18'} + + '@commitlint/config-validator@19.8.0': + resolution: {integrity: sha512-+r5ZvD/0hQC3w5VOHJhGcCooiAVdynFlCe2d6I9dU+PvXdV3O+fU4vipVg+6hyLbQUuCH82mz3HnT/cBQTYYuA==} + engines: {node: '>=v18'} + + '@commitlint/ensure@19.8.0': + resolution: {integrity: sha512-kNiNU4/bhEQ/wutI1tp1pVW1mQ0QbAjfPRo5v8SaxoVV+ARhkB8Wjg3BSseNYECPzWWfg/WDqQGIfV1RaBFQZg==} + engines: {node: '>=v18'} + + '@commitlint/execute-rule@19.8.0': + resolution: {integrity: sha512-fuLeI+EZ9x2v/+TXKAjplBJWI9CNrHnyi5nvUQGQt4WRkww/d95oVRsc9ajpt4xFrFmqMZkd/xBQHZDvALIY7A==} + engines: {node: '>=v18'} + + '@commitlint/format@19.8.0': + resolution: {integrity: sha512-EOpA8IERpQstxwp/WGnDArA7S+wlZDeTeKi98WMOvaDLKbjptuHWdOYYr790iO7kTCif/z971PKPI2PkWMfOxg==} + engines: {node: '>=v18'} + + '@commitlint/is-ignored@19.8.0': + resolution: {integrity: sha512-L2Jv9yUg/I+jF3zikOV0rdiHUul9X3a/oU5HIXhAJLE2+TXTnEBfqYP9G5yMw/Yb40SnR764g4fyDK6WR2xtpw==} + engines: {node: '>=v18'} + + '@commitlint/lint@19.8.0': + resolution: {integrity: sha512-+/NZKyWKSf39FeNpqhfMebmaLa1P90i1Nrb1SrA7oSU5GNN/lksA4z6+ZTnsft01YfhRZSYMbgGsARXvkr/VLQ==} + engines: {node: '>=v18'} + + '@commitlint/load@19.8.0': + resolution: {integrity: sha512-4rvmm3ff81Sfb+mcWT5WKlyOa+Hd33WSbirTVUer0wjS1Hv/Hzr07Uv1ULIV9DkimZKNyOwXn593c+h8lsDQPQ==} + engines: {node: '>=v18'} + + '@commitlint/message@19.8.0': + resolution: {integrity: sha512-qs/5Vi9bYjf+ZV40bvdCyBn5DvbuelhR6qewLE8Bh476F7KnNyLfdM/ETJ4cp96WgeeHo6tesA2TMXS0sh5X4A==} + engines: {node: '>=v18'} + + '@commitlint/parse@19.8.0': + resolution: {integrity: sha512-YNIKAc4EXvNeAvyeEnzgvm1VyAe0/b3Wax7pjJSwXuhqIQ1/t2hD3OYRXb6D5/GffIvaX82RbjD+nWtMZCLL7Q==} + engines: {node: '>=v18'} + + '@commitlint/read@19.8.0': + resolution: {integrity: sha512-6ywxOGYajcxK1y1MfzrOnwsXO6nnErna88gRWEl3qqOOP8MDu/DTeRkGLXBFIZuRZ7mm5yyxU5BmeUvMpNte5w==} + engines: {node: '>=v18'} + + '@commitlint/resolve-extends@19.8.0': + resolution: {integrity: sha512-CLanRQwuG2LPfFVvrkTrBR/L/DMy3+ETsgBqW1OvRxmzp/bbVJW0Xw23LnnExgYcsaFtos967lul1CsbsnJlzQ==} + engines: {node: '>=v18'} + + '@commitlint/rules@19.8.0': + resolution: {integrity: sha512-IZ5IE90h6DSWNuNK/cwjABLAKdy8tP8OgGVGbXe1noBEX5hSsu00uRlLu6JuruiXjWJz2dZc+YSw3H0UZyl/mA==} + engines: {node: '>=v18'} + + '@commitlint/to-lines@19.8.0': + resolution: {integrity: sha512-3CKLUw41Cur8VMjh16y8LcsOaKbmQjAKCWlXx6B0vOUREplp6em9uIVhI8Cv934qiwkbi2+uv+mVZPnXJi1o9A==} + engines: {node: '>=v18'} + + '@commitlint/top-level@19.8.0': + resolution: {integrity: sha512-Rphgoc/omYZisoNkcfaBRPQr4myZEHhLPx2/vTXNLjiCw4RgfPR1wEgUpJ9OOmDCiv5ZyIExhprNLhteqH4FuQ==} + engines: {node: '>=v18'} + + '@commitlint/types@19.8.0': + resolution: {integrity: sha512-LRjP623jPyf3Poyfb0ohMj8I3ORyBDOwXAgxxVPbSD0unJuW2mJWeiRfaQinjtccMqC5Wy1HOMfa4btKjbNxbg==} + engines: {node: '>=v18'} + + '@csstools/css-parser-algorithms@3.0.4': + resolution: {integrity: sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-tokenizer': ^3.0.3 + + '@csstools/css-tokenizer@3.0.3': + resolution: {integrity: sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==} + engines: {node: '>=18'} + + '@csstools/media-query-list-parser@4.0.2': + resolution: {integrity: sha512-EUos465uvVvMJehckATTlNqGj4UJWkTmdWuDMjqvSUkjGpmOyFZBVwb4knxCm/k2GMTXY+c/5RkdndzFYWeX5A==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.4 + '@csstools/css-tokenizer': ^3.0.3 + + '@csstools/selector-specificity@5.0.0': + resolution: {integrity: sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==} + engines: {node: '>=18'} + peerDependencies: + postcss-selector-parser: ^7.0.0 + + '@ctrl/tinycolor@3.6.1': + resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} + engines: {node: '>=10'} + + '@dual-bundle/import-meta-resolve@4.1.0': + resolution: {integrity: sha512-+nxncfwHM5SgAtrVzgpzJOI1ol0PkumhVo469KCf9lUi21IGcY90G98VuHm9VRrUypmAzawAHO9bs6hqeADaVg==} + + '@element-plus/icons-vue@2.3.1': + resolution: {integrity: sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==} + peerDependencies: + vue: ^3.2.0 + + '@esbuild/aix-ppc64@0.24.2': + resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.25.3': + resolution: {integrity: sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.24.2': + resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.25.3': + resolution: {integrity: sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.24.2': + resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.25.3': + resolution: {integrity: sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.24.2': + resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.25.3': + resolution: {integrity: sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.24.2': + resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.25.3': + resolution: {integrity: sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.24.2': + resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.3': + resolution: {integrity: sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.24.2': + resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.25.3': + resolution: {integrity: sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.24.2': + resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.3': + resolution: {integrity: sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.24.2': + resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.25.3': + resolution: {integrity: sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.24.2': + resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.25.3': + resolution: {integrity: sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.24.2': + resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.25.3': + resolution: {integrity: sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.24.2': + resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.25.3': + resolution: {integrity: sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.24.2': + resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.25.3': + resolution: {integrity: sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.24.2': + resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.25.3': + resolution: {integrity: sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.24.2': + resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.3': + resolution: {integrity: sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.24.2': + resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.25.3': + resolution: {integrity: sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.24.2': + resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.25.3': + resolution: {integrity: sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.24.2': + resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-arm64@0.25.3': + resolution: {integrity: sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.24.2': + resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.3': + resolution: {integrity: sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.24.2': + resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.25.3': + resolution: {integrity: sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.24.2': + resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.3': + resolution: {integrity: sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.24.2': + resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.25.3': + resolution: {integrity: sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.24.2': + resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.25.3': + resolution: {integrity: sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.24.2': + resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.25.3': + resolution: {integrity: sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.24.2': + resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.25.3': + resolution: {integrity: sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.6.1': + resolution: {integrity: sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.20.0': + resolution: {integrity: sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.2.1': + resolution: {integrity: sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.13.0': + resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.1': + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.25.1': + resolution: {integrity: sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.6': + resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.2.8': + resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@faker-js/faker@9.7.0': + resolution: {integrity: sha512-aozo5vqjCmDoXLNUJarFZx2IN/GgGaogY4TMJ6so/WLZOWpSV7fvj2dmrV6sEAnUm1O7aCrhTibjpzeDFgNqbg==} + engines: {node: '>=18.0.0', npm: '>=9.0.0'} + + '@floating-ui/core@1.6.9': + resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==} + + '@floating-ui/dom@1.6.13': + resolution: {integrity: sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==} + + '@floating-ui/utils@0.2.9': + resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.6': + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.3.1': + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} + + '@humanwhocodes/retry@0.4.2': + resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} + engines: {node: '>=18.18'} + + '@iconify/json@2.2.331': + resolution: {integrity: sha512-K8hDKDFJ31nF2mERN6Nfxv4peXZfaN4kmZqeBpCRhHA/5/SCp+hx9ID4kLH3lEhBm1eqmXfZjwOC2v7FnaFHYw==} + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@2.3.0': + resolution: {integrity: sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==} + + '@iconify/vue@4.2.0': + resolution: {integrity: sha512-CMynoz9BDWugDO2B7LU/s8L99dHCiqDGCjCki6bhVx5etZhw9x0BTV7wWRdj82jtl1yQTc+QQRcHQmSvUY6R+g==} + peerDependencies: + vue: '>=3' + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@jridgewell/gen-mapping@0.3.8': + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@keyv/serialize@1.0.3': + resolution: {integrity: sha512-qnEovoOp5Np2JDGonIDL6Ayihw0RhnRh6vxPuHo4RDn1UOzwEo4AeIfpL6UGIrsceWrCMiVPgwRjbHu4vYFc3g==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nuxt/kit@3.16.2': + resolution: {integrity: sha512-K1SAUo2vweTfudKZzjKsZ5YJoxPLTspR5qz5+G61xtZreLpsdpDYfBseqsIAl5VFLJuszeRpWQ01jP9LfQ6Ksw==} + engines: {node: '>=18.12.0'} + + '@parcel/watcher-android-arm64@2.5.1': + resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.1': + resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.1': + resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.1': + resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.1': + resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-arm-musl@2.5.1': + resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [musl] + + '@parcel/watcher-linux-arm64-glibc@2.5.1': + resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-arm64-musl@2.5.1': + resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@parcel/watcher-linux-x64-glibc@2.5.1': + resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-x64-musl@2.5.1': + resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@parcel/watcher-win32-arm64@2.5.1': + resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.1': + resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.1': + resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.1': + resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} + engines: {node: '>= 10.0.0'} + + '@pkgr/core@0.2.4': + resolution: {integrity: sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@popperjs/core@2.11.8': + resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + + '@pureadmin/descriptions@1.2.1': + resolution: {integrity: sha512-7jDJuqz8xnhcmwXdWQnBzOYeX2WK27TRFaVgs9AdiRr+DnKb9W+krHByJwQtxo5lg4qyRh4/IWQGEMfhC2ljeQ==} + peerDependencies: + element-plus: ^2.0.0 + + '@pureadmin/table@3.2.1': + resolution: {integrity: sha512-sqkAQWRDx6X0dADUgrYHvA7QfocF+VB5rPe1yFQWjh7tcHNasthFRDCS5Fmw7JQ0R3h6S7aBK450ye2/TLv4JQ==} + peerDependencies: + element-plus: ^2.0.0 + + '@pureadmin/utils@2.6.0': + resolution: {integrity: sha512-xPncBQ4DZUstKrljsHxr3yuYacEZmvEilSfrZ6vpWNgJtPnViJ24Lf7gl7c1Y1RKYm/kXxjrhI7x69S2oN1Pvg==} + peerDependencies: + echarts: '*' + vue: '*' + peerDependenciesMeta: + echarts: + optional: true + vue: + optional: true + + '@rollup/pluginutils@5.1.4': + resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.40.0': + resolution: {integrity: sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.40.0': + resolution: {integrity: sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.40.0': + resolution: {integrity: sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.40.0': + resolution: {integrity: sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.40.0': + resolution: {integrity: sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.40.0': + resolution: {integrity: sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.40.0': + resolution: {integrity: sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.40.0': + resolution: {integrity: sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.40.0': + resolution: {integrity: sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.40.0': + resolution: {integrity: sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loongarch64-gnu@4.40.0': + resolution: {integrity: sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-powerpc64le-gnu@4.40.0': + resolution: {integrity: sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-gnu@4.40.0': + resolution: {integrity: sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.40.0': + resolution: {integrity: sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.40.0': + resolution: {integrity: sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.40.0': + resolution: {integrity: sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.40.0': + resolution: {integrity: sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-win32-arm64-msvc@4.40.0': + resolution: {integrity: sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.40.0': + resolution: {integrity: sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.40.0': + resolution: {integrity: sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==} + cpu: [x64] + os: [win32] + + '@sindresorhus/merge-streams@2.3.0': + resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} + engines: {node: '>=18'} + + '@sxzz/popperjs-es@2.11.7': + resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==} + + '@tailwindcss/node@4.1.4': + resolution: {integrity: sha512-MT5118zaiO6x6hNA04OWInuAiP1YISXql8Z+/Y8iisV5nuhM8VXlyhRuqc2PEviPszcXI66W44bCIk500Oolhw==} + + '@tailwindcss/oxide-android-arm64@4.1.4': + resolution: {integrity: sha512-xMMAe/SaCN/vHfQYui3fqaBDEXMu22BVwQ33veLc8ep+DNy7CWN52L+TTG9y1K397w9nkzv+Mw+mZWISiqhmlA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.4': + resolution: {integrity: sha512-JGRj0SYFuDuAGilWFBlshcexev2hOKfNkoX+0QTksKYq2zgF9VY/vVMq9m8IObYnLna0Xlg+ytCi2FN2rOL0Sg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.4': + resolution: {integrity: sha512-sdDeLNvs3cYeWsEJ4H1DvjOzaGios4QbBTNLVLVs0XQ0V95bffT3+scptzYGPMjm7xv4+qMhCDrkHwhnUySEzA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.4': + resolution: {integrity: sha512-VHxAqxqdghM83HslPhRsNhHo91McsxRJaEnShJOMu8mHmEj9Ig7ToHJtDukkuLWLzLboh2XSjq/0zO6wgvykNA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.4': + resolution: {integrity: sha512-OTU/m/eV4gQKxy9r5acuesqaymyeSCnsx1cFto/I1WhPmi5HDxX1nkzb8KYBiwkHIGg7CTfo/AcGzoXAJBxLfg==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.4': + resolution: {integrity: sha512-hKlLNvbmUC6z5g/J4H+Zx7f7w15whSVImokLPmP6ff1QqTVE+TxUM9PGuNsjHvkvlHUtGTdDnOvGNSEUiXI1Ww==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.4': + resolution: {integrity: sha512-X3As2xhtgPTY/m5edUtddmZ8rCruvBvtxYLMw9OsZdH01L2gS2icsHRwxdU0dMItNfVmrBezueXZCHxVeeb7Aw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.4': + resolution: {integrity: sha512-2VG4DqhGaDSmYIu6C4ua2vSLXnJsb/C9liej7TuSO04NK+JJJgJucDUgmX6sn7Gw3Cs5ZJ9ZLrnI0QRDOjLfNQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.1.4': + resolution: {integrity: sha512-v+mxVgH2kmur/X5Mdrz9m7TsoVjbdYQT0b4Z+dr+I4RvreCNXyCFELZL/DO0M1RsidZTrm6O1eMnV6zlgEzTMQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.1.4': + resolution: {integrity: sha512-2TLe9ir+9esCf6Wm+lLWTMbgklIjiF0pbmDnwmhR9MksVOq+e8aP3TSsXySnBDDvTTVd/vKu1aNttEGj3P6l8Q==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.4': + resolution: {integrity: sha512-VlnhfilPlO0ltxW9/BgfLI5547PYzqBMPIzRrk4W7uupgCt8z6Trw/tAj6QUtF2om+1MH281Pg+HHUJoLesmng==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.4': + resolution: {integrity: sha512-+7S63t5zhYjslUGb8NcgLpFXD+Kq1F/zt5Xv5qTv7HaFTG/DHyHD9GA6ieNAxhgyA4IcKa/zy7Xx4Oad2/wuhw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.4': + resolution: {integrity: sha512-p5wOpXyOJx7mKh5MXh5oKk+kqcz8T+bA3z/5VWWeQwFrmuBItGwz8Y2CHk/sJ+dNb9B0nYFfn0rj/cKHZyjahQ==} + engines: {node: '>= 10'} + + '@tailwindcss/vite@4.1.4': + resolution: {integrity: sha512-4UQeMrONbvrsXKXXp/uxmdEN5JIJ9RkH7YVzs6AMxC/KC1+Np7WZBaNIco7TEjlkthqxZbt8pU/ipD+hKjm80A==} + peerDependencies: + vite: ^5.2.0 || ^6 + + '@trysound/sax@0.2.0': + resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} + engines: {node: '>=10.13.0'} + + '@types/conventional-commits-parser@5.0.1': + resolution: {integrity: sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ==} + + '@types/estree@1.0.7': + resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + + '@types/js-cookie@3.0.6': + resolution: {integrity: sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/lodash-es@4.17.12': + resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} + + '@types/lodash@4.17.16': + resolution: {integrity: sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==} + + '@types/node@20.17.30': + resolution: {integrity: sha512-7zf4YyHA+jvBNfVrk2Gtvs6x7E8V+YDW05bNfG2XkWDJfYRXrTiP/DsB2zSYTaHX0bGIujTBQdMVAhb+j7mwpg==} + + '@types/nprogress@0.2.3': + resolution: {integrity: sha512-k7kRA033QNtC+gLc4VPlfnue58CM1iQLgn1IMAU8VPHGOj7oIHPp9UlhedEnD/Gl8evoCjwkZjlBORtZ3JByUA==} + + '@types/path-browserify@1.0.3': + resolution: {integrity: sha512-ZmHivEbNCBtAfcrFeBCiTjdIc2dey0l7oCGNGpSuRTy8jP6UVND7oUowlvDujBy8r2Hoa8bfFUOCiPWfmtkfxw==} + + '@types/qs@6.9.18': + resolution: {integrity: sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==} + + '@types/sortablejs@1.15.8': + resolution: {integrity: sha512-b79830lW+RZfwaztgs1aVPgbasJ8e7AXtZYHTELNXZPsERt4ymJdjV4OccDbHQAvHrCcFpbF78jkm0R6h/pZVg==} + + '@types/tinycolor2@1.4.6': + resolution: {integrity: sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==} + + '@types/web-bluetooth@0.0.16': + resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==} + + '@types/web-bluetooth@0.0.21': + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + + '@typescript-eslint/eslint-plugin@8.31.0': + resolution: {integrity: sha512-evaQJZ/J/S4wisevDvC1KFZkPzRetH8kYZbkgcTRyql3mcKsf+ZFDV1BVWUGTCAW5pQHoqn5gK5b8kn7ou9aFQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/parser@8.31.0': + resolution: {integrity: sha512-67kYYShjBR0jNI5vsf/c3WG4u+zDnCTHTPqVMQguffaWWFs7artgwKmfwdifl+r6XyM5LYLas/dInj2T0SgJyw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/scope-manager@8.31.0': + resolution: {integrity: sha512-knO8UyF78Nt8O/B64i7TlGXod69ko7z6vJD9uhSlm0qkAbGeRUSudcm0+K/4CrRjrpiHfBCjMWlc08Vav1xwcw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/type-utils@8.31.0': + resolution: {integrity: sha512-DJ1N1GdjI7IS7uRlzJuEDCgDQix3ZVYVtgeWEyhyn4iaoitpMBX6Ndd488mXSx0xah/cONAkEaYyylDyAeHMHg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/types@8.31.0': + resolution: {integrity: sha512-Ch8oSjVyYyJxPQk8pMiP2FFGYatqXQfQIaMp+TpuuLlDachRWpUAeEu1u9B/v/8LToehUIWyiKcA/w5hUFRKuQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.31.0': + resolution: {integrity: sha512-xLmgn4Yl46xi6aDSZ9KkyfhhtnYI15/CvHbpOy/eR5NWhK/BK8wc709KKwhAR0m4ZKRP7h07bm4BWUYOCuRpQQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/utils@8.31.0': + resolution: {integrity: sha512-qi6uPLt9cjTFxAb1zGNgTob4x9ur7xC6mHQJ8GwEzGMGE9tYniublmJaowOJ9V2jUzxrltTPfdG2nKlWsq0+Ww==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/visitor-keys@8.31.0': + resolution: {integrity: sha512-QcGHmlRHWOl93o64ZUMNewCdwKGU6WItOU52H0djgNmn1EOrhVudrDzXz4OycCRSCPwFCDrE2iIt5vmuUdHxuQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@vitejs/plugin-vue-jsx@4.1.2': + resolution: {integrity: sha512-4Rk0GdE0QCdsIkuMmWeg11gmM4x8UmTnZR/LWPm7QJ7+BsK4tq08udrN0isrrWqz5heFy9HLV/7bOLgFS8hUjA==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 + vue: ^3.0.0 + + '@vitejs/plugin-vue@5.2.3': + resolution: {integrity: sha512-IYSLEQj4LgZZuoVpdSUCw3dIynTWQgPlaRP6iAvMle4My0HdYwr5g5wQAfwOeHQBmYwEkqF70nRpSilr6PoUDg==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 + vue: ^3.2.25 + + '@volar/language-core@2.4.12': + resolution: {integrity: sha512-RLrFdXEaQBWfSnYGVxvR2WrO6Bub0unkdHYIdC31HzIEqATIuuhRRzYu76iGPZ6OtA4Au1SnW0ZwIqPP217YhA==} + + '@volar/source-map@2.4.12': + resolution: {integrity: sha512-bUFIKvn2U0AWojOaqf63ER0N/iHIBYZPpNGogfLPQ68F5Eet6FnLlyho7BS0y2HJ1jFhSif7AcuTx1TqsCzRzw==} + + '@volar/typescript@2.4.12': + resolution: {integrity: sha512-HJB73OTJDgPc80K30wxi3if4fSsZZAOScbj2fcicMuOPoOkcf9NNAINb33o+DzhBdF9xTKC1gnPmIRDous5S0g==} + + '@vue/babel-helper-vue-transform-on@1.4.0': + resolution: {integrity: sha512-mCokbouEQ/ocRce/FpKCRItGo+013tHg7tixg3DUNS+6bmIchPt66012kBMm476vyEIJPafrvOf4E5OYj3shSw==} + + '@vue/babel-plugin-jsx@1.4.0': + resolution: {integrity: sha512-9zAHmwgMWlaN6qRKdrg1uKsBKHvnUU+Py+MOCTuYZBoZsopa90Di10QRjB+YPnVss0BZbG/H5XFwJY1fTxJWhA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + peerDependenciesMeta: + '@babel/core': + optional: true + + '@vue/babel-plugin-resolve-type@1.4.0': + resolution: {integrity: sha512-4xqDRRbQQEWHQyjlYSgZsWj44KfiF6D+ktCuXyZ8EnVDYV3pztmXJDf1HveAjUAXxAnR8daCQT51RneWWxtTyQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@vue/compiler-core@3.5.13': + resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} + + '@vue/compiler-dom@3.5.13': + resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} + + '@vue/compiler-sfc@3.5.13': + resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} + + '@vue/compiler-ssr@3.5.13': + resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} + + '@vue/compiler-vue2@2.7.16': + resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} + + '@vue/devtools-api@6.6.4': + resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} + + '@vue/devtools-api@7.7.5': + resolution: {integrity: sha512-HYV3tJGARROq5nlVMJh5KKHk7GU8Au3IrrmNNqr978m0edxgpHgYPDoNUGrvEgIbObz09SQezFR3A1EVmB5WZg==} + + '@vue/devtools-kit@7.7.5': + resolution: {integrity: sha512-S9VAVJYVAe4RPx2JZb9ZTEi0lqTySz2CBeF0wHT5D3dkTLnT9yMMGegKNl4b2EIELwLSkcI9bl2qp0/jW+upqA==} + + '@vue/devtools-shared@7.7.5': + resolution: {integrity: sha512-QBjG72RfpM0DKtpns2RZOxBltO226kOAls9e4Lri6YxS2gWTgL0H+wj1R2K76lxxIeOrqo4+2Ty6RQnzv+WSTQ==} + + '@vue/language-core@2.2.10': + resolution: {integrity: sha512-+yNoYx6XIKuAO8Mqh1vGytu8jkFEOH5C8iOv3i8Z/65A7x9iAOXA97Q+PqZ3nlm2lxf5rOJuIGI/wDtx/riNYw==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@vue/reactivity@3.5.13': + resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} + + '@vue/runtime-core@3.5.13': + resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==} + + '@vue/runtime-dom@3.5.13': + resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==} + + '@vue/server-renderer@3.5.13': + resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==} + peerDependencies: + vue: 3.5.13 + + '@vue/shared@3.5.13': + resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} + + '@vueuse/core@13.1.0': + resolution: {integrity: sha512-PAauvdRXZvTWXtGLg8cPUFjiZEddTqmogdwYpnn60t08AA5a8Q4hZokBnpTOnVNqySlFlTcRYIC8OqreV4hv3Q==} + peerDependencies: + vue: ^3.5.0 + + '@vueuse/core@9.13.0': + resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==} + + '@vueuse/metadata@13.1.0': + resolution: {integrity: sha512-+TDd7/a78jale5YbHX9KHW3cEDav1lz1JptwDvep2zSG8XjCsVE+9mHIzjTOaPbHUAk5XiE4jXLz51/tS+aKQw==} + + '@vueuse/metadata@9.13.0': + resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==} + + '@vueuse/motion@3.0.3': + resolution: {integrity: sha512-4B+ITsxCI9cojikvrpaJcLXyq0spj3sdlzXjzesWdMRd99hhtFI6OJ/1JsqwtF73YooLe0hUn/xDR6qCtmn5GQ==} + peerDependencies: + vue: '>=3.0.0' + + '@vueuse/shared@13.1.0': + resolution: {integrity: sha512-IVS/qRRjhPTZ6C2/AM3jieqXACGwFZwWTdw5sNTSKk2m/ZpkuuN+ri+WCVUP8TqaKwJYt/KuMwmXspMAw8E6ew==} + peerDependencies: + vue: ^3.5.0 + + '@vueuse/shared@9.13.0': + resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==} + + JSONStream@1.3.5: + resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} + hasBin: true + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.14.1: + resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + alien-signals@1.0.13: + resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==} + + animate.css@4.1.1: + resolution: {integrity: sha512-+mRmCTv6SbCmtYJCN4faJMNFVNN5EuCTTprDTAo7YzIGji2KADmakjVA3+8mVDkZ2Bf09vayB35lSQIex2+QaQ==} + + ansi-align@3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + + ansi-escapes@7.0.0: + resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} + engines: {node: '>=18'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-ify@1.0.0: + resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + + async-validator@4.2.5: + resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.9.0: + resolution: {integrity: sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + balanced-match@2.0.0: + resolution: {integrity: sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + birpc@2.3.0: + resolution: {integrity: sha512-ijbtkn/F3Pvzb6jHypHRyve2QApOCZDR25D/VnkY2G/lBNcXCTsnsCxgY4k4PkVB7zfwzYbY3O9Lcqe3xufS5g==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + boxen@8.0.1: + resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==} + engines: {node: '>=18'} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.24.4: + resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + bundle-import@0.0.2: + resolution: {integrity: sha512-XB3T6xlgqJHThyr2luo3pNAVhfN/Y2qFEsblrzUO5QZLpJtesget8jmGDImSairScy80ZKBDVcRdFzTzWv3v8A==} + + c12@3.0.3: + resolution: {integrity: sha512-uC3MacKBb0Z15o5QWCHvHWj5Zv34pGQj9P+iXKSpTuSGFS0KKhUWf4t9AJ+gWjYOdmWCPEGpEzm8sS0iqbpo1w==} + peerDependencies: + magicast: ^0.3.5 + peerDependenciesMeta: + magicast: + optional: true + + cacheable@1.8.10: + resolution: {integrity: sha512-0ZnbicB/N2R6uziva8l6O6BieBklArWyiGx4GkwAhLKhSHyQtRfM9T1nx7HHuHDKkYB/efJQhz3QJ6x/YqoZzA==} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@8.0.0: + resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} + engines: {node: '>=16'} + + caniuse-api@3.0.0: + resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} + + caniuse-lite@1.0.30001715: + resolution: {integrity: sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==} + + chalk@4.1.1: + resolution: {integrity: sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==} + engines: {node: '>=10'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + + cli-boxes@3.0.0: + resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} + engines: {node: '>=10'} + + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + + cli-truncate@4.0.0: + resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} + engines: {node: '>=18'} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + code-inspector-core@0.20.10: + resolution: {integrity: sha512-nSIn1nKJ58BIKhrr4Kiv39ZyIOFKVD1oxVZVf98CSuKz559llCjcyY0DjI8MzZG6iimw5/myemOxhYrV9jUvDQ==} + + code-inspector-plugin@0.20.10: + resolution: {integrity: sha512-G3aQ+t65N+rJlydPRUoG4vegjQb3seitCXCuNICUMhkDLetdVONLTASePVPCADv+fXl0vyW0hnZzAAxb9UnwOQ==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + colord@2.9.3: + resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@13.1.0: + resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} + engines: {node: '>=18'} + + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + compare-func@2.0.0: + resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.2: + resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + + conventional-changelog-angular@7.0.0: + resolution: {integrity: sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==} + engines: {node: '>=16'} + + conventional-changelog-conventionalcommits@7.0.2: + resolution: {integrity: sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==} + engines: {node: '>=16'} + + conventional-commits-parser@5.0.0: + resolution: {integrity: sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==} + engines: {node: '>=16'} + hasBin: true + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + copy-anything@3.0.5: + resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} + engines: {node: '>=12.13'} + + cosmiconfig-typescript-loader@6.1.0: + resolution: {integrity: sha512-tJ1w35ZRUiM5FeTzT7DtYWAFFv37ZLqSRkGi2oeCK1gPhvaWjkAtfXvLmvE1pRfxxp9aQo6ba/Pvg1dKj05D4g==} + engines: {node: '>=v18'} + peerDependencies: + '@types/node': '*' + cosmiconfig: '>=9' + typescript: '>=5' + + cosmiconfig@9.0.0: + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + css-declaration-sorter@7.2.0: + resolution: {integrity: sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + postcss: ^8.0.9 + + css-functions-list@3.2.3: + resolution: {integrity: sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==} + engines: {node: '>=12 || >=16'} + + css-select@5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + + css-tree@2.2.1: + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + css-tree@2.3.1: + resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css-tree@3.1.0: + resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css-what@6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + cssnano-preset-default@7.0.6: + resolution: {integrity: sha512-ZzrgYupYxEvdGGuqL+JKOY70s7+saoNlHSCK/OGn1vB2pQK8KSET8jvenzItcY+kA7NoWvfbb/YhlzuzNKjOhQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + cssnano-utils@5.0.0: + resolution: {integrity: sha512-Uij0Xdxc24L6SirFr25MlwC2rCFX6scyUmuKpzI+JQ7cyqDEwD42fJ0xfB3yLfOnRDU5LKGgjQ9FA6LYh76GWQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + cssnano@7.0.6: + resolution: {integrity: sha512-54woqx8SCbp8HwvNZYn68ZFAepuouZW4lTwiMVnBErM3VkO7/Sd4oTOt3Zz3bPx3kxQ36aISppyXj2Md4lg8bw==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + csso@5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + dargs@8.1.0: + resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==} + engines: {node: '>=12'} + + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + + de-indent@1.0.2: + resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + + detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + + detect-libc@2.0.4: + resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} + engines: {node: '>=8'} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + + dot-prop@5.3.0: + resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} + engines: {node: '>=8'} + + dotenv@16.5.0: + resolution: {integrity: sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==} + engines: {node: '>=12'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + echarts@5.6.0: + resolution: {integrity: sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==} + + electron-to-chromium@1.5.142: + resolution: {integrity: sha512-Ah2HgkTu/9RhTDNThBtzu2Wirdy4DC9b0sMT1pUhbkZQ5U/iwmE+PHZX1MpjD5IkJCc2wSghgGG/B04szAx07w==} + + element-plus@2.9.8: + resolution: {integrity: sha512-srViUaUdfblBKGMeuEPiXxxKlH5aUmKqEwmhb/At9Sj91DbU6od/jYN1955cTnzt3wTSA7GfnZF7UiRX9sdRHg==} + peerDependencies: + vue: ^3.2.0 + + emoji-regex@10.4.0: + resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + enhanced-resolve@5.18.1: + resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} + engines: {node: '>=10.13.0'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + errx@0.1.0: + resolution: {integrity: sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@0.4.1: + resolution: {integrity: sha512-ooYciCUtfw6/d2w56UVeqHPcoCFAiJdz5XOkYpv/Txl1HMUozpXjz/2RIQgqwKdXNDPSF1W7mJCFse3G+HDyAA==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + esbuild-code-inspector-plugin@0.20.10: + resolution: {integrity: sha512-sYedVx+EjEnIEvomYJdW93wm5vPLuXer0cwj7kmNA1nnsz1hqF5XVrBheqVAMGMj7kM7erKu0hMLJUz0znpzWQ==} + + esbuild@0.24.2: + resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.25.3: + resolution: {integrity: sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + eslint-config-prettier@10.1.2: + resolution: {integrity: sha512-Epgp/EofAUeEpIdZkW60MHKvPyru1ruQJxPL+WIycnaPApuseK0Zpkrh/FwL9oIpQvIhJwV7ptOy0DWUjTlCiA==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-plugin-prettier@5.2.6: + resolution: {integrity: sha512-mUcf7QG2Tjk7H055Jk0lGBjbgDnfrvqjhXh9t2xLMSCjZVcw9Rb1V6sVNXO0th3jgeO7zllWPTNRil3JW94TnQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + + eslint-plugin-vue@10.0.0: + resolution: {integrity: sha512-XKckedtajqwmaX6u1VnECmZ6xJt+YvlmMzBPZd+/sI3ub2lpYZyFnsyWo7c3nMOQKJQudeyk1lw/JxdgeKT64w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + vue-eslint-parser: ^10.0.0 + + eslint-scope@8.3.0: + resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.0: + resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.25.1: + resolution: {integrity: sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.3.0: + resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + exsolve@1.0.5: + resolution: {integrity: sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-uri@3.0.6: + resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} + + fastest-levenshtein@1.0.16: + resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} + engines: {node: '>= 4.9.1'} + + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + + fdir@6.4.4: + resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@10.0.8: + resolution: {integrity: sha512-FGXHpfmI4XyzbLd3HQ8cbUcsFGohJpZtmQRHr8z8FxxtCe2PcpgIlVLwIgunqjvRmXypBETvwhV4ptJizA+Y1Q==} + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + find-up@7.0.0: + resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==} + engines: {node: '>=18'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flat-cache@6.1.8: + resolution: {integrity: sha512-R6MaD3nrJAtO7C3QOuS79ficm2pEAy++TgEUD8ii1LVlbcgZ9DtASLkt9B+RZSFCzm7QHDMlXPsqqB6W2Pfr1Q==} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + form-data@4.0.2: + resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} + engines: {node: '>= 6'} + + framesync@6.1.2: + resolution: {integrity: sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g==} + + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-east-asian-width@1.3.0: + resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==} + engines: {node: '>=18'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + get-tsconfig@4.10.0: + resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==} + + giget@2.0.0: + resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} + hasBin: true + + git-raw-commits@4.0.0: + resolution: {integrity: sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==} + engines: {node: '>=16'} + hasBin: true + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@11.0.2: + resolution: {integrity: sha512-YT7U7Vye+t5fZ/QMkBFrTJ7ZQxInIUjwyAjVj84CYXqgBdv30MFUPGnBR6sQaVq6Is15wYJUsnzTuWaGRBhBAQ==} + engines: {node: 20 || >=22} + hasBin: true + + global-directory@4.0.1: + resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} + engines: {node: '>=18'} + + global-modules@2.0.0: + resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} + engines: {node: '>=6'} + + global-prefix@3.0.0: + resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} + engines: {node: '>=6'} + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@15.15.0: + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + engines: {node: '>=18'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + globby@14.1.0: + resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==} + engines: {node: '>=18'} + + globjoin@0.1.4: + resolution: {integrity: sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + gradient-string@3.0.0: + resolution: {integrity: sha512-frdKI4Qi8Ihp4C6wZNB565de/THpIaw3DjP5ku87M+N9rNSGmPTjfkq61SdRXB7eCaL8O1hkKDvf6CDMtOzIAg==} + engines: {node: '>=14'} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + hey-listen@1.0.8: + resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==} + + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + + hookified@1.8.2: + resolution: {integrity: sha512-5nZbBNP44sFCDjSoB//0N7m508APCgbQ4mGGo1KJGBYyCKNHfry1Pvd0JVHZIxjdnqn8nFRBAN/eFB6Rk/4w5w==} + + html-tags@3.3.1: + resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} + engines: {node: '>=8'} + + htmlparser2@8.0.2: + resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + husky@9.1.7: + resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} + engines: {node: '>=18'} + hasBin: true + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.3: + resolution: {integrity: sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==} + engines: {node: '>= 4'} + + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + + immutable@5.1.1: + resolution: {integrity: sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg==} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + import-from-string@0.0.5: + resolution: {integrity: sha512-z59WIHImWhnGVswc0JoyI10Qn4A8xQw7OKrCFRQHvzGZhhEixX13OtXP9ud3Xjpn16CUoYfh5mTu3tnNODiSAw==} + + import-meta-resolve@4.1.0: + resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + ini@4.1.1: + resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + + is-fullwidth-code-point@5.0.0: + resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==} + engines: {node: '>=18'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-obj@2.0.0: + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} + + is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + + is-reference@3.0.3: + resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-text-path@2.0.0: + resolution: {integrity: sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==} + engines: {node: '>=8'} + + is-what@4.1.16: + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} + + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jackspeak@4.1.0: + resolution: {integrity: sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==} + engines: {node: 20 || >=22} + + jiti@2.4.2: + resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} + hasBin: true + + js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + + jsonparse@1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + keyv@5.3.3: + resolution: {integrity: sha512-Rwu4+nXI9fqcxiEHtbkvoes2X+QfkTRo1TMkPfwzipGsJlJO/z69vqB4FNl9xJ3xCpAcbkvmEabZfPzrwN3+gQ==} + + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + + klona@2.0.6: + resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} + engines: {node: '>= 8'} + + knitwork@1.2.0: + resolution: {integrity: sha512-xYSH7AvuQ6nXkq42x0v5S8/Iry+cfulBz/DJQzhIyESdLD7425jXsPy4vn5cCXU+HhRN2kVw51Vd1K6/By4BQg==} + + known-css-properties@0.35.0: + resolution: {integrity: sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==} + + known-css-properties@0.36.0: + resolution: {integrity: sha512-A+9jP+IUmuQsNdsLdcg6Yt7voiMF/D4K83ew0OpJtpu+l34ef7LaohWV0Rc6KNvzw6ZDizkqfyB5JznZnzuKQA==} + + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + + launch-ide@1.0.7: + resolution: {integrity: sha512-wJMTq6U2sVYqxrlp544KQxtl8cHoXFfQa2ivDtKJ6ock2ARneiEHqUFce/NQsnNP1aZNg4OXB6g00oFRvni1/Q==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lie@3.1.1: + resolution: {integrity: sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==} + + lightningcss-darwin-arm64@1.29.2: + resolution: {integrity: sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.29.2: + resolution: {integrity: sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.29.2: + resolution: {integrity: sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.29.2: + resolution: {integrity: sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.29.2: + resolution: {integrity: sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.29.2: + resolution: {integrity: sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.29.2: + resolution: {integrity: sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.29.2: + resolution: {integrity: sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.29.2: + resolution: {integrity: sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.29.2: + resolution: {integrity: sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.29.2: + resolution: {integrity: sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==} + engines: {node: '>= 12.0.0'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + lint-staged@15.5.1: + resolution: {integrity: sha512-6m7u8mue4Xn6wK6gZvSCQwBvMBR36xfY24nF5bMTf2MHDYG6S3yhJuOgdYVw99hsjyDt2d4z168b3naI8+NWtQ==} + engines: {node: '>=18.12.0'} + hasBin: true + + listr2@8.3.2: + resolution: {integrity: sha512-vsBzcU4oE+v0lj4FhVLzr9dBTv4/fHIa57l+GCwovP8MoFNZJTOhGU8PXd4v2VJCbECAaijBiHntiekFMLvo0g==} + engines: {node: '>=18.0.0'} + + local-pkg@1.1.1: + resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==} + engines: {node: '>=14'} + + localforage@1.10.0: + resolution: {integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + locate-path@7.2.0: + resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + + lodash-unified@1.0.3: + resolution: {integrity: sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==} + peerDependencies: + '@types/lodash-es': '*' + lodash: '*' + lodash-es: '*' + + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.kebabcase@4.1.1: + resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} + + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.mergewith@4.6.2: + resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} + + lodash.snakecase@4.1.1: + resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} + + lodash.startcase@4.4.0: + resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + + lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + + lodash.uniq@4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + + lodash.upperfirst@4.3.1: + resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} + + lru-cache@11.1.0: + resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==} + engines: {node: 20 || >=22} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + magic-string@0.25.9: + resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} + + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mathml-tag-names@2.1.3: + resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==} + + mdn-data@2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + + mdn-data@2.0.30: + resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + + mdn-data@2.12.2: + resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + + mdn-data@2.21.0: + resolution: {integrity: sha512-+ZKPQezM5vYJIkCxaC+4DTnRrVZR1CgsKLu5zsQERQx6Tea8Y+wMx5A24rq8A8NepCeatIQufVAekKNgiBMsGQ==} + + memoize-one@6.0.0: + resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} + + meow@12.1.1: + resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} + engines: {node: '>=16.10'} + + meow@13.2.0: + resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} + engines: {node: '>=18'} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + + minimatch@10.0.1: + resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} + engines: {node: 20 || >=22} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + + mlly@1.7.4: + resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + + node-fetch-native@1.6.6: + resolution: {integrity: sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==} + + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-wheel-es@1.2.0: + resolution: {integrity: sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==} + + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + nprogress@0.2.0: + resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + nypm@0.6.0: + resolution: {integrity: sha512-mn8wBFV9G9+UFHIrq+pZ2r2zL4aPau/by3kJb3cM7+5tQHMt6HGQB8FDIeKFYp8o0D2pnH6nVsO88N4AmUxIWg==} + engines: {node: ^14.16.0 || >=16.10.0} + hasBin: true + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-locate@6.0.0: + resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + package-manager-detector@0.2.11: + resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-exists@5.0.0: + resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + + path-to-regexp@8.2.0: + resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} + engines: {node: '>=16'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + path-type@6.0.0: + resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==} + engines: {node: '>=18'} + + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + + pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} + engines: {node: '>=0.10'} + hasBin: true + + pinia@3.0.2: + resolution: {integrity: sha512-sH2JK3wNY809JOeiiURUR0wehJ9/gd9qFN2Y828jCbxEzKEmEt0pzCXwqiSTfuRsK9vQsOflSdnbdBOGrhtn+g==} + peerDependencies: + typescript: '>=4.4.4' + vue: ^2.7.0 || ^3.5.11 + peerDependenciesMeta: + typescript: + optional: true + + pinyin-pro@3.26.0: + resolution: {integrity: sha512-HcBZZb0pvm0/JkPhZHWA5Hqp2cWHXrrW/WrV+OtaYYM+kf35ffvZppIUuGmyuQ7gDr1JDJKMkbEE+GN0wfMoGg==} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-types@2.1.0: + resolution: {integrity: sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==} + + popmotion@11.0.5: + resolution: {integrity: sha512-la8gPM1WYeFznb/JqF4GiTkRRPZsfaj2+kCxqQgr2MJylMmIKUwBfWW8Wa5fml/8gmtlD5yI01MP1QCZPWmppA==} + + portfinder@1.0.36: + resolution: {integrity: sha512-gMKUzCoP+feA7t45moaSx7UniU7PgGN3hA8acAB+3Qn7/js0/lJ07fYZlxt9riE9S3myyxDCyAFzSrLlta0c9g==} + engines: {node: '>= 10.12'} + + postcss-calc@10.1.1: + resolution: {integrity: sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==} + engines: {node: ^18.12 || ^20.9 || >=22.0} + peerDependencies: + postcss: ^8.4.38 + + postcss-colormin@7.0.2: + resolution: {integrity: sha512-YntRXNngcvEvDbEjTdRWGU606eZvB5prmHG4BF0yLmVpamXbpsRJzevyy6MZVyuecgzI2AWAlvFi8DAeCqwpvA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-convert-values@7.0.4: + resolution: {integrity: sha512-e2LSXPqEHVW6aoGbjV9RsSSNDO3A0rZLCBxN24zvxF25WknMPpX8Dm9UxxThyEbaytzggRuZxaGXqaOhxQ514Q==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-discard-comments@7.0.3: + resolution: {integrity: sha512-q6fjd4WU4afNhWOA2WltHgCbkRhZPgQe7cXF74fuVB/ge4QbM9HEaOIzGSiMvM+g/cOsNAUGdf2JDzqA2F8iLA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-discard-duplicates@7.0.1: + resolution: {integrity: sha512-oZA+v8Jkpu1ct/xbbrntHRsfLGuzoP+cpt0nJe5ED2FQF8n8bJtn7Bo28jSmBYwqgqnqkuSXJfSUEE7if4nClQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-discard-empty@7.0.0: + resolution: {integrity: sha512-e+QzoReTZ8IAwhnSdp/++7gBZ/F+nBq9y6PomfwORfP7q9nBpK5AMP64kOt0bA+lShBFbBDcgpJ3X4etHg4lzA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-discard-overridden@7.0.0: + resolution: {integrity: sha512-GmNAzx88u3k2+sBTZrJSDauR0ccpE24omTQCVmaTTZFz1du6AasspjaUPMJ2ud4RslZpoFKyf+6MSPETLojc6w==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-html@1.8.0: + resolution: {integrity: sha512-5mMeb1TgLWoRKxZ0Xh9RZDfwUUIqRrcxO2uXO+Ezl1N5lqpCiSU5Gk6+1kZediBfBHFtPCdopr2UZ2SgUsKcgQ==} + engines: {node: ^12 || >=14} + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss-media-query-parser@0.2.3: + resolution: {integrity: sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==} + + postcss-merge-longhand@7.0.4: + resolution: {integrity: sha512-zer1KoZA54Q8RVHKOY5vMke0cCdNxMP3KBfDerjH/BYHh4nCIh+1Yy0t1pAEQF18ac/4z3OFclO+ZVH8azjR4A==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-merge-rules@7.0.4: + resolution: {integrity: sha512-ZsaamiMVu7uBYsIdGtKJ64PkcQt6Pcpep/uO90EpLS3dxJi6OXamIobTYcImyXGoW0Wpugh7DSD3XzxZS9JCPg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-minify-font-values@7.0.0: + resolution: {integrity: sha512-2ckkZtgT0zG8SMc5aoNwtm5234eUx1GGFJKf2b1bSp8UflqaeFzR50lid4PfqVI9NtGqJ2J4Y7fwvnP/u1cQog==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-minify-gradients@7.0.0: + resolution: {integrity: sha512-pdUIIdj/C93ryCHew0UgBnL2DtUS3hfFa5XtERrs4x+hmpMYGhbzo6l/Ir5de41O0GaKVpK1ZbDNXSY6GkXvtg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-minify-params@7.0.2: + resolution: {integrity: sha512-nyqVLu4MFl9df32zTsdcLqCFfE/z2+f8GE1KHPxWOAmegSo6lpV2GNy5XQvrzwbLmiU7d+fYay4cwto1oNdAaQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-minify-selectors@7.0.4: + resolution: {integrity: sha512-JG55VADcNb4xFCf75hXkzc1rNeURhlo7ugf6JjiiKRfMsKlDzN9CXHZDyiG6x/zGchpjQS+UAgb1d4nqXqOpmA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-normalize-charset@7.0.0: + resolution: {integrity: sha512-ABisNUXMeZeDNzCQxPxBCkXexvBrUHV+p7/BXOY+ulxkcjUZO0cp8ekGBwvIh2LbCwnWbyMPNJVtBSdyhM2zYQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-normalize-display-values@7.0.0: + resolution: {integrity: sha512-lnFZzNPeDf5uGMPYgGOw7v0BfB45+irSRz9gHQStdkkhiM0gTfvWkWB5BMxpn0OqgOQuZG/mRlZyJxp0EImr2Q==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-normalize-positions@7.0.0: + resolution: {integrity: sha512-I0yt8wX529UKIGs2y/9Ybs2CelSvItfmvg/DBIjTnoUSrPxSV7Z0yZ8ShSVtKNaV/wAY+m7bgtyVQLhB00A1NQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-normalize-repeat-style@7.0.0: + resolution: {integrity: sha512-o3uSGYH+2q30ieM3ppu9GTjSXIzOrRdCUn8UOMGNw7Af61bmurHTWI87hRybrP6xDHvOe5WlAj3XzN6vEO8jLw==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-normalize-string@7.0.0: + resolution: {integrity: sha512-w/qzL212DFVOpMy3UGyxrND+Kb0fvCiBBujiaONIihq7VvtC7bswjWgKQU/w4VcRyDD8gpfqUiBQ4DUOwEJ6Qg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-normalize-timing-functions@7.0.0: + resolution: {integrity: sha512-tNgw3YV0LYoRwg43N3lTe3AEWZ66W7Dh7lVEpJbHoKOuHc1sLrzMLMFjP8SNULHaykzsonUEDbKedv8C+7ej6g==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-normalize-unicode@7.0.2: + resolution: {integrity: sha512-ztisabK5C/+ZWBdYC+Y9JCkp3M9qBv/XFvDtSw0d/XwfT3UaKeW/YTm/MD/QrPNxuecia46vkfEhewjwcYFjkg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-normalize-url@7.0.0: + resolution: {integrity: sha512-+d7+PpE+jyPX1hDQZYG+NaFD+Nd2ris6r8fPTBAjE8z/U41n/bib3vze8x7rKs5H1uEw5ppe9IojewouHk0klQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-normalize-whitespace@7.0.0: + resolution: {integrity: sha512-37/toN4wwZErqohedXYqWgvcHUGlT8O/m2jVkAfAe9Bd4MzRqlBmXrJRePH0e9Wgnz2X7KymTgTOaaFizQe3AQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-ordered-values@7.0.1: + resolution: {integrity: sha512-irWScWRL6nRzYmBOXReIKch75RRhNS86UPUAxXdmW/l0FcAsg0lvAXQCby/1lymxn/o0gVa6Rv/0f03eJOwHxw==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-reduce-initial@7.0.2: + resolution: {integrity: sha512-pOnu9zqQww7dEKf62Nuju6JgsW2V0KRNBHxeKohU+JkHd/GAH5uvoObqFLqkeB2n20mr6yrlWDvo5UBU5GnkfA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-reduce-transforms@7.0.0: + resolution: {integrity: sha512-pnt1HKKZ07/idH8cpATX/ujMbtOGhUfE+m8gbqwJE05aTaNw8gbo34a2e3if0xc0dlu75sUOiqvwCGY3fzOHew==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-resolve-nested-selector@0.1.6: + resolution: {integrity: sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==} + + postcss-safe-parser@6.0.0: + resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.3.3 + + postcss-safe-parser@7.0.1: + resolution: {integrity: sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==} + engines: {node: '>=18.0'} + peerDependencies: + postcss: ^8.4.31 + + postcss-scss@4.0.9: + resolution: {integrity: sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.4.29 + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + + postcss-selector-parser@7.1.0: + resolution: {integrity: sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==} + engines: {node: '>=4'} + + postcss-sorting@8.0.2: + resolution: {integrity: sha512-M9dkSrmU00t/jK7rF6BZSZauA5MAaBW4i5EnJXspMwt4iqTh/L9j6fgMnbElEOfyRyfLfVbIHj/R52zHzAPe1Q==} + peerDependencies: + postcss: ^8.4.20 + + postcss-svgo@7.0.1: + resolution: {integrity: sha512-0WBUlSL4lhD9rA5k1e5D8EN5wCEyZD6HJk0jIvRxl+FDVOMlJ7DePHYWGGVc5QRqrJ3/06FTXM0bxjmJpmTPSA==} + engines: {node: ^18.12.0 || ^20.9.0 || >= 18} + peerDependencies: + postcss: ^8.4.31 + + postcss-unique-selectors@7.0.3: + resolution: {integrity: sha512-J+58u5Ic5T1QjP/LDV9g3Cx4CNOgB5vz+kM6+OxHHhFACdcDeKhBXjQmB7fnIZM12YSTvsL0Opwco83DmacW2g==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.3: + resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier@3.5.3: + resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} + engines: {node: '>=14'} + hasBin: true + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + + quansync@0.2.10: + resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + rc9@2.1.2: + resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + responsive-storage@2.2.0: + resolution: {integrity: sha512-94W5Chr2F5kDBT6J+OCOeJguEkSTDc3jPOUQXYmzNG64DCNl5p7hoBDF7bx7u6EXAEcpUKF64OZR4b7Nn8h/Gg==} + + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + + rimraf@6.0.1: + resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} + engines: {node: 20 || >=22} + hasBin: true + + rollup-plugin-external-globals@0.10.0: + resolution: {integrity: sha512-RXlupZrmn97AaaS5dWnktkjM+Iy+od0E+8L0mUkMIs3iuoUXNJebueQocQKV7Ircd54fSGGmkBaXwNzY05J1yQ==} + peerDependencies: + rollup: ^2.25.0 || ^3.3.0 || ^4.1.4 + + rollup-plugin-visualizer@5.14.0: + resolution: {integrity: sha512-VlDXneTDaKsHIw8yzJAFWtrzguoJ/LnQ+lMpoVfYJ3jJF4Ihe5oYLAqLklIK/35lgUY+1yEzCkHyZ1j4A5w5fA==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + rolldown: 1.x + rollup: 2.x || 3.x || 4.x + peerDependenciesMeta: + rolldown: + optional: true + rollup: + optional: true + + rollup@4.40.0: + resolution: {integrity: sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + sass@1.87.0: + resolution: {integrity: sha512-d0NoFH4v6SjEK7BoX810Jsrhj7IQSYHAHLi/iSpgqKc7LaIDshFRlSg5LOymf9FqQhxEHs2W5ZQXlvy0KD45Uw==} + engines: {node: '>=14.0.0'} + hasBin: true + + scule@1.3.0: + resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.1: + resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + + slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + + slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + + slice-ansi@7.1.0: + resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==} + engines: {node: '>=18'} + + sortablejs@1.15.6: + resolution: {integrity: sha512-aNfiuwMEpfBM/CN6LY0ibyhxPfPbyFeBTYJKCvzkJ2GkUpazIt3H+QIPAMHwqQ7tMKaHz1Qj+rJJCqljnf4p3A==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + + sourcemap-codec@1.4.8: + resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} + deprecated: Please use @jridgewell/sourcemap-codec instead + + speakingurl@14.0.1: + resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} + engines: {node: '>=0.10.0'} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + std-env@3.9.0: + resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + strip-literal@3.0.0: + resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} + + style-value-types@5.1.2: + resolution: {integrity: sha512-Vs9fNreYF9j6W2VvuDTP7kepALi7sk0xtk2Tu8Yxi9UoajJdEVpNpCov0HsLTqXvNGKX+Uv09pkozVITi1jf3Q==} + + stylehacks@7.0.4: + resolution: {integrity: sha512-i4zfNrGMt9SB4xRK9L83rlsFCgdGANfeDAYacO1pkqcE7cRHPdWHwnKZVz7WY17Veq/FvyYsRAU++Ga+qDFIww==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + stylelint-config-html@1.1.0: + resolution: {integrity: sha512-IZv4IVESjKLumUGi+HWeb7skgO6/g4VMuAYrJdlqQFndgbj6WJAXPhaysvBiXefX79upBdQVumgYcdd17gCpjQ==} + engines: {node: ^12 || >=14} + peerDependencies: + postcss-html: ^1.0.0 + stylelint: '>=14.0.0' + + stylelint-config-recess-order@6.0.0: + resolution: {integrity: sha512-1KqrttqpIrCYFAVQ1/bbgXo7EvvcjmkxxmnzVr+U66Xr2OlrNZqQ5+44Tmct6grCWY6wGTIBh2tSANqcmwIM2g==} + peerDependencies: + stylelint: '>=16' + + stylelint-config-recommended-scss@14.1.0: + resolution: {integrity: sha512-bhaMhh1u5dQqSsf6ri2GVWWQW5iUjBYgcHkh7SgDDn92ijoItC/cfO/W+fpXshgTQWhwFkP1rVcewcv4jaftRg==} + engines: {node: '>=18.12.0'} + peerDependencies: + postcss: ^8.3.3 + stylelint: ^16.6.1 + peerDependenciesMeta: + postcss: + optional: true + + stylelint-config-recommended-vue@1.6.0: + resolution: {integrity: sha512-syk1adIHvbH2T1OiR/spUK4oQy35PZIDw8Zmc7E0+eVK9Z9SK3tdMpGRT/bgGnAPpMt/WaL9K1u0tlF6xM0sMQ==} + engines: {node: ^12 || >=14} + peerDependencies: + postcss-html: ^1.0.0 + stylelint: '>=14.0.0' + + stylelint-config-recommended@14.0.1: + resolution: {integrity: sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg==} + engines: {node: '>=18.12.0'} + peerDependencies: + stylelint: ^16.1.0 + + stylelint-config-recommended@16.0.0: + resolution: {integrity: sha512-4RSmPjQegF34wNcK1e1O3Uz91HN8P1aFdFzio90wNK9mjgAI19u5vsU868cVZboKzCaa5XbpvtTzAAGQAxpcXA==} + engines: {node: '>=18.12.0'} + peerDependencies: + stylelint: ^16.16.0 + + stylelint-config-standard-scss@14.0.0: + resolution: {integrity: sha512-6Pa26D9mHyi4LauJ83ls3ELqCglU6VfCXchovbEqQUiEkezvKdv6VgsIoMy58i00c854wVmOw0k8W5FTpuaVqg==} + engines: {node: '>=18.12.0'} + peerDependencies: + postcss: ^8.3.3 + stylelint: ^16.11.0 + peerDependenciesMeta: + postcss: + optional: true + + stylelint-config-standard@36.0.1: + resolution: {integrity: sha512-8aX8mTzJ6cuO8mmD5yon61CWuIM4UD8Q5aBcWKGSf6kg+EC3uhB+iOywpTK4ca6ZL7B49en8yanOFtUW0qNzyw==} + engines: {node: '>=18.12.0'} + peerDependencies: + stylelint: ^16.1.0 + + stylelint-order@6.0.4: + resolution: {integrity: sha512-0UuKo4+s1hgQ/uAxlYU4h0o0HS4NiQDud0NAUNI0aa8FJdmYHA5ZZTFHiV5FpmE3071e9pZx5j0QpVJW5zOCUA==} + peerDependencies: + stylelint: ^14.0.0 || ^15.0.0 || ^16.0.1 + + stylelint-prettier@5.0.3: + resolution: {integrity: sha512-B6V0oa35ekRrKZlf+6+jA+i50C4GXJ7X1PPmoCqSUoXN6BrNF6NhqqhanvkLjqw2qgvrS0wjdpeC+Tn06KN3jw==} + engines: {node: '>=18.12.0'} + peerDependencies: + prettier: '>=3.0.0' + stylelint: '>=16.0.0' + + stylelint-scss@6.11.1: + resolution: {integrity: sha512-e4rYo0UY+BIMtGeGanghrvHTjcryxgZbyFxUedp8dLFqC4P70aawNdYjRrQxbnKhu3BNr4+lt5e/53tcKXiwFA==} + engines: {node: '>=18.12.0'} + peerDependencies: + stylelint: ^16.0.2 + + stylelint@16.19.0: + resolution: {integrity: sha512-BJzc5mo/ez0H/ZSl3UbxGdkK/s0kFGsF5/k6IGu4z8wJ1qp49WrOS9RxswvcN6HMirt0g/iiJqOwLHTbWv49IQ==} + engines: {node: '>=18.12.0'} + hasBin: true + + superjson@2.2.2: + resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} + engines: {node: '>=16'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-hyperlinks@3.2.0: + resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==} + engines: {node: '>=14.18'} + + svg-tags@1.0.0: + resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==} + + svgo@3.3.2: + resolution: {integrity: sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==} + engines: {node: '>=14.0.0'} + hasBin: true + + synckit@0.11.4: + resolution: {integrity: sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ==} + engines: {node: ^14.18.0 || >=16.0.0} + + table@6.9.0: + resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} + engines: {node: '>=10.0.0'} + + tailwindcss@4.1.4: + resolution: {integrity: sha512-1ZIUqtPITFbv/DxRmDr5/agPqJwF69d24m9qmM1939TJehgY539CtzeZRjbLt5G6fSy/7YqqYsfvoTEw9xUI2A==} + + tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + + text-extensions@2.4.0: + resolution: {integrity: sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==} + engines: {node: '>=8'} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + tinycolor2@1.6.0: + resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.13: + resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} + engines: {node: '>=12.0.0'} + + tinygradient@1.1.5: + resolution: {integrity: sha512-8nIfc2vgQ4TeLnk2lFj4tRLvvJwEfQuabdsmvDdQPT0xlk9TaNtpGd6nNRxXoK6vQhN6RSzj+Cnp5tTQmpxmbw==} + + tippy.js@6.3.7: + resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tslib@2.3.0: + resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==} + + tslib@2.4.0: + resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@4.40.0: + resolution: {integrity: sha512-ABHZ2/tS2JkvH1PEjxFDTUWC8dB5OsIGZP4IFLhR293GqT5Y5qB1WwL2kMPYhQW9DVgVD8Hd7I8gjwPIf5GFkw==} + engines: {node: '>=16'} + + typescript-eslint@8.31.0: + resolution: {integrity: sha512-u+93F0sB0An8WEAPtwxVhFby573E8ckdjwUUQUj9QA4v8JAvgtoDdIyYR3XFwFHq2W1KJ1AurwJCO+w+Y1ixyQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + + typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + + unctx@2.4.1: + resolution: {integrity: sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==} + + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + unicorn-magic@0.1.0: + resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + engines: {node: '>=18'} + + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} + engines: {node: '>=18'} + + unimport@4.2.0: + resolution: {integrity: sha512-mYVtA0nmzrysnYnyb3ALMbByJ+Maosee2+WyE0puXl+Xm2bUwPorPaaeZt0ETfuroPOtG8jj1g/qeFZ6buFnag==} + engines: {node: '>=18.12.0'} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unplugin-icons@22.1.0: + resolution: {integrity: sha512-ect2ZNtk1Zgwb0NVHd0C1IDW/MV+Jk/xaq4t8o6rYdVS3+L660ZdD5kTSQZvsgdwCvquRw+/wYn75hsweRjoIA==} + peerDependencies: + '@svgr/core': '>=7.0.0' + '@svgx/core': ^1.0.1 + '@vue/compiler-sfc': ^3.0.2 || ^2.7.0 + svelte: ^3.0.0 || ^4.0.0 || ^5.0.0 + vue-template-compiler: ^2.6.12 + vue-template-es2015-compiler: ^1.9.0 + peerDependenciesMeta: + '@svgr/core': + optional: true + '@svgx/core': + optional: true + '@vue/compiler-sfc': + optional: true + svelte: + optional: true + vue-template-compiler: + optional: true + vue-template-es2015-compiler: + optional: true + + unplugin-utils@0.2.4: + resolution: {integrity: sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA==} + engines: {node: '>=18.12.0'} + + unplugin@2.3.2: + resolution: {integrity: sha512-3n7YA46rROb3zSj8fFxtxC/PqoyvYQ0llwz9wtUPUutr9ig09C8gGo5CWCwHrUzlqC1LLR43kxp5vEIyH1ac1w==} + engines: {node: '>=18.12.0'} + + untyped@2.0.0: + resolution: {integrity: sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g==} + hasBin: true + + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vite-code-inspector-plugin@0.20.10: + resolution: {integrity: sha512-uE5nwooHTi3j1+ZWD4bYydiLGjtY8Nn/be2OEnHyXC0UQv4vM5fsB8V3glszWaQ+ip0yJw+VLtfgf1mVpvf7Mg==} + + vite-plugin-cdn-import@1.0.1: + resolution: {integrity: sha512-lgjLxgwFSKvJLbqjVBirUZ0rQo00GpUGJzRpgQu8RyBw9LA7jaqG6fUMQzBC9qWmTGabPC3iOzwCcoi7PseRAQ==} + + vite-plugin-compression@0.5.1: + resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==} + peerDependencies: + vite: '>=2.0.0' + + vite-plugin-externals@0.6.2: + resolution: {integrity: sha512-R5oVY8xDJjLXLTs2XDYzvYbc/RTZuIwOx2xcFbYf+/VXB6eJuatDgt8jzQ7kZ+IrgwQhe6tU8U2fTyy72C25CQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: '>=2.0.0' + + vite-plugin-fake-server@2.2.0: + resolution: {integrity: sha512-RP691997Q207nenNMhg7cvYyBXZyjqXwApTBa+a9kHmILgcAU2w4TMRDiAhIU0HPLAAR5MHlWTEpxA9Tbf+v8g==} + + vite-plugin-remove-console@2.2.0: + resolution: {integrity: sha512-qgjh5pz75MdE9Kzs8J0kBwaCfifHV0ezRbB9rpGsIOxam+ilcGV7WOk91vFJXquzRmiKrFh3Hxlh0JJWAmXTbQ==} + + vite-plugin-router-warn@1.0.0: + resolution: {integrity: sha512-jnr7faHJPkKxukBXVpg7Ui1UDqhmxD7xU6JGidq8ivSHTsNAPqzSpPpwW8O1PBP/0+Owq4bLfNNk11drOkz4xA==} + + vite-svg-loader@5.1.0: + resolution: {integrity: sha512-M/wqwtOEjgb956/+m5ZrYT/Iq6Hax0OakWbokj8+9PXOnB7b/4AxESHieEtnNEy7ZpjsjYW1/5nK8fATQMmRxw==} + peerDependencies: + vue: '>=3.2.13' + + vite@6.3.3: + resolution: {integrity: sha512-5nXH+QsELbFKhsEfWLkHrvgRpTdGJzqOZ+utSdmPTvwHmvU6ITTm3xx+mRusihkcI8GeC7lCDyn3kDtiki9scw==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + + vue-demi@0.14.10: + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + vue-eslint-parser@10.1.3: + resolution: {integrity: sha512-dbCBnd2e02dYWsXoqX5yKUZlOt+ExIpq7hmHKPb5ZqKcjf++Eo0hMseFTZMLKThrUk61m+Uv6A2YSBve6ZvuDQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + + vue-router@4.5.0: + resolution: {integrity: sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==} + peerDependencies: + vue: ^3.2.0 + + vue-tippy@6.7.0: + resolution: {integrity: sha512-e0w6UA+A+J79GhDYNw5xZjGu7Tc2ksYypwF5RjkJVWgAGNSpXkLVNx4gZ8cMUa8FRHqmGAZxN3ue7MeXgbeZAQ==} + peerDependencies: + vue: ^3.2.0 + + vue-tsc@2.2.10: + resolution: {integrity: sha512-jWZ1xSaNbabEV3whpIDMbjVSVawjAyW+x1n3JeGQo7S0uv2n9F/JMgWW90tGWNFRKya4YwKMZgCtr0vRAM7DeQ==} + hasBin: true + peerDependencies: + typescript: '>=5.0.0' + + vue-types@6.0.0: + resolution: {integrity: sha512-fBgCA4nrBrB8SCU/AN40tFq8HUxLGBvU2ds7a5+SEDse6dYc+TJyvy8mWiwwL8oWIC/aGS/8nTqmhwxApgU5eA==} + engines: {node: '>=14.0.0'} + peerDependencies: + vue: ^3.0.0 + peerDependenciesMeta: + vue: + optional: true + + vue@3.5.13: + resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + webpack-code-inspector-plugin@0.20.10: + resolution: {integrity: sha512-I8mSEVbwMtQ1SSdb9pLK7VHqykobdrLvAgbZSKzrGQUGsmTbLmpVTJVs6EJgV1rsl5aoi1BKgmdr77CqaDSnfA==} + + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + + which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + widest-line@5.0.0: + resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==} + engines: {node: '>=18'} + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrap-ansi@9.0.0: + resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} + engines: {node: '>=18'} + + write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + xml-name-validator@4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yaml@2.7.1: + resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==} + engines: {node: '>= 14'} + hasBin: true + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yocto-queue@1.2.1: + resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==} + engines: {node: '>=12.20'} + + zrender@5.6.1: + resolution: {integrity: sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + + '@antfu/install-pkg@1.0.0': + dependencies: + package-manager-detector: 0.2.11 + tinyexec: 0.3.2 + + '@antfu/utils@8.1.1': {} + + '@babel/code-frame@7.26.2': + dependencies: + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.26.8': {} + + '@babel/core@7.26.10': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.27.0 + '@babel/helper-compilation-targets': 7.27.0 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.10) + '@babel/helpers': 7.27.0 + '@babel/parser': 7.27.0 + '@babel/template': 7.27.0 + '@babel/traverse': 7.27.0 + '@babel/types': 7.27.0 + convert-source-map: 2.0.0 + debug: 4.4.0 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.27.0': + dependencies: + '@babel/parser': 7.27.0 + '@babel/types': 7.27.0 + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.1.0 + + '@babel/helper-annotate-as-pure@7.25.9': + dependencies: + '@babel/types': 7.27.0 + + '@babel/helper-compilation-targets@7.27.0': + dependencies: + '@babel/compat-data': 7.26.8 + '@babel/helper-validator-option': 7.25.9 + browserslist: 4.24.4 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.27.0(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-member-expression-to-functions': 7.25.9 + '@babel/helper-optimise-call-expression': 7.25.9 + '@babel/helper-replace-supers': 7.26.5(@babel/core@7.26.10) + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/traverse': 7.27.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-member-expression-to-functions@7.25.9': + dependencies: + '@babel/traverse': 7.27.0 + '@babel/types': 7.27.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.25.9': + dependencies: + '@babel/traverse': 7.27.0 + '@babel/types': 7.27.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.27.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-optimise-call-expression@7.25.9': + dependencies: + '@babel/types': 7.27.0 + + '@babel/helper-plugin-utils@7.26.5': {} + + '@babel/helper-replace-supers@7.26.5(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-member-expression-to-functions': 7.25.9 + '@babel/helper-optimise-call-expression': 7.25.9 + '@babel/traverse': 7.27.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.25.9': + dependencies: + '@babel/traverse': 7.27.0 + '@babel/types': 7.27.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.25.9': {} + + '@babel/helper-validator-identifier@7.25.9': {} + + '@babel/helper-validator-option@7.25.9': {} + + '@babel/helpers@7.27.0': + dependencies: + '@babel/template': 7.27.0 + '@babel/types': 7.27.0 + + '@babel/parser@7.27.0': + dependencies: + '@babel/types': 7.27.0 + + '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-typescript@7.27.0(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-create-class-features-plugin': 7.27.0(@babel/core@7.26.10) + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.10) + transitivePeerDependencies: + - supports-color + + '@babel/template@7.27.0': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/parser': 7.27.0 + '@babel/types': 7.27.0 + + '@babel/traverse@7.27.0': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.27.0 + '@babel/parser': 7.27.0 + '@babel/template': 7.27.0 + '@babel/types': 7.27.0 + debug: 4.4.0 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.27.0': + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + + '@commitlint/cli@19.8.0(@types/node@20.17.30)(typescript@5.8.3)': + dependencies: + '@commitlint/format': 19.8.0 + '@commitlint/lint': 19.8.0 + '@commitlint/load': 19.8.0(@types/node@20.17.30)(typescript@5.8.3) + '@commitlint/read': 19.8.0 + '@commitlint/types': 19.8.0 + tinyexec: 0.3.2 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - typescript + + '@commitlint/config-conventional@19.8.0': + dependencies: + '@commitlint/types': 19.8.0 + conventional-changelog-conventionalcommits: 7.0.2 + + '@commitlint/config-validator@19.8.0': + dependencies: + '@commitlint/types': 19.8.0 + ajv: 8.17.1 + + '@commitlint/ensure@19.8.0': + dependencies: + '@commitlint/types': 19.8.0 + lodash.camelcase: 4.3.0 + lodash.kebabcase: 4.1.1 + lodash.snakecase: 4.1.1 + lodash.startcase: 4.4.0 + lodash.upperfirst: 4.3.1 + + '@commitlint/execute-rule@19.8.0': {} + + '@commitlint/format@19.8.0': + dependencies: + '@commitlint/types': 19.8.0 + chalk: 5.4.1 + + '@commitlint/is-ignored@19.8.0': + dependencies: + '@commitlint/types': 19.8.0 + semver: 7.7.1 + + '@commitlint/lint@19.8.0': + dependencies: + '@commitlint/is-ignored': 19.8.0 + '@commitlint/parse': 19.8.0 + '@commitlint/rules': 19.8.0 + '@commitlint/types': 19.8.0 + + '@commitlint/load@19.8.0(@types/node@20.17.30)(typescript@5.8.3)': + dependencies: + '@commitlint/config-validator': 19.8.0 + '@commitlint/execute-rule': 19.8.0 + '@commitlint/resolve-extends': 19.8.0 + '@commitlint/types': 19.8.0 + chalk: 5.4.1 + cosmiconfig: 9.0.0(typescript@5.8.3) + cosmiconfig-typescript-loader: 6.1.0(@types/node@20.17.30)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3) + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + lodash.uniq: 4.5.0 + transitivePeerDependencies: + - '@types/node' + - typescript + + '@commitlint/message@19.8.0': {} + + '@commitlint/parse@19.8.0': + dependencies: + '@commitlint/types': 19.8.0 + conventional-changelog-angular: 7.0.0 + conventional-commits-parser: 5.0.0 + + '@commitlint/read@19.8.0': + dependencies: + '@commitlint/top-level': 19.8.0 + '@commitlint/types': 19.8.0 + git-raw-commits: 4.0.0 + minimist: 1.2.8 + tinyexec: 0.3.2 + + '@commitlint/resolve-extends@19.8.0': + dependencies: + '@commitlint/config-validator': 19.8.0 + '@commitlint/types': 19.8.0 + global-directory: 4.0.1 + import-meta-resolve: 4.1.0 + lodash.mergewith: 4.6.2 + resolve-from: 5.0.0 + + '@commitlint/rules@19.8.0': + dependencies: + '@commitlint/ensure': 19.8.0 + '@commitlint/message': 19.8.0 + '@commitlint/to-lines': 19.8.0 + '@commitlint/types': 19.8.0 + + '@commitlint/to-lines@19.8.0': {} + + '@commitlint/top-level@19.8.0': + dependencies: + find-up: 7.0.0 + + '@commitlint/types@19.8.0': + dependencies: + '@types/conventional-commits-parser': 5.0.1 + chalk: 5.4.1 + + '@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3)': + dependencies: + '@csstools/css-tokenizer': 3.0.3 + + '@csstools/css-tokenizer@3.0.3': {} + + '@csstools/media-query-list-parser@4.0.2(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3) + '@csstools/css-tokenizer': 3.0.3 + + '@csstools/selector-specificity@5.0.0(postcss-selector-parser@7.1.0)': + dependencies: + postcss-selector-parser: 7.1.0 + + '@ctrl/tinycolor@3.6.1': {} + + '@dual-bundle/import-meta-resolve@4.1.0': {} + + '@element-plus/icons-vue@2.3.1(vue@3.5.13(typescript@5.8.3))': + dependencies: + vue: 3.5.13(typescript@5.8.3) + + '@esbuild/aix-ppc64@0.24.2': + optional: true + + '@esbuild/aix-ppc64@0.25.3': + optional: true + + '@esbuild/android-arm64@0.24.2': + optional: true + + '@esbuild/android-arm64@0.25.3': + optional: true + + '@esbuild/android-arm@0.24.2': + optional: true + + '@esbuild/android-arm@0.25.3': + optional: true + + '@esbuild/android-x64@0.24.2': + optional: true + + '@esbuild/android-x64@0.25.3': + optional: true + + '@esbuild/darwin-arm64@0.24.2': + optional: true + + '@esbuild/darwin-arm64@0.25.3': + optional: true + + '@esbuild/darwin-x64@0.24.2': + optional: true + + '@esbuild/darwin-x64@0.25.3': + optional: true + + '@esbuild/freebsd-arm64@0.24.2': + optional: true + + '@esbuild/freebsd-arm64@0.25.3': + optional: true + + '@esbuild/freebsd-x64@0.24.2': + optional: true + + '@esbuild/freebsd-x64@0.25.3': + optional: true + + '@esbuild/linux-arm64@0.24.2': + optional: true + + '@esbuild/linux-arm64@0.25.3': + optional: true + + '@esbuild/linux-arm@0.24.2': + optional: true + + '@esbuild/linux-arm@0.25.3': + optional: true + + '@esbuild/linux-ia32@0.24.2': + optional: true + + '@esbuild/linux-ia32@0.25.3': + optional: true + + '@esbuild/linux-loong64@0.24.2': + optional: true + + '@esbuild/linux-loong64@0.25.3': + optional: true + + '@esbuild/linux-mips64el@0.24.2': + optional: true + + '@esbuild/linux-mips64el@0.25.3': + optional: true + + '@esbuild/linux-ppc64@0.24.2': + optional: true + + '@esbuild/linux-ppc64@0.25.3': + optional: true + + '@esbuild/linux-riscv64@0.24.2': + optional: true + + '@esbuild/linux-riscv64@0.25.3': + optional: true + + '@esbuild/linux-s390x@0.24.2': + optional: true + + '@esbuild/linux-s390x@0.25.3': + optional: true + + '@esbuild/linux-x64@0.24.2': + optional: true + + '@esbuild/linux-x64@0.25.3': + optional: true + + '@esbuild/netbsd-arm64@0.24.2': + optional: true + + '@esbuild/netbsd-arm64@0.25.3': + optional: true + + '@esbuild/netbsd-x64@0.24.2': + optional: true + + '@esbuild/netbsd-x64@0.25.3': + optional: true + + '@esbuild/openbsd-arm64@0.24.2': + optional: true + + '@esbuild/openbsd-arm64@0.25.3': + optional: true + + '@esbuild/openbsd-x64@0.24.2': + optional: true + + '@esbuild/openbsd-x64@0.25.3': + optional: true + + '@esbuild/sunos-x64@0.24.2': + optional: true + + '@esbuild/sunos-x64@0.25.3': + optional: true + + '@esbuild/win32-arm64@0.24.2': + optional: true + + '@esbuild/win32-arm64@0.25.3': + optional: true + + '@esbuild/win32-ia32@0.24.2': + optional: true + + '@esbuild/win32-ia32@0.25.3': + optional: true + + '@esbuild/win32-x64@0.24.2': + optional: true + + '@esbuild/win32-x64@0.25.3': + optional: true + + '@eslint-community/eslint-utils@4.6.1(eslint@9.25.1(jiti@2.4.2))': + dependencies: + eslint: 9.25.1(jiti@2.4.2) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/config-array@0.20.0': + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.0 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.2.1': {} + + '@eslint/core@0.13.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.1': + dependencies: + ajv: 6.12.6 + debug: 4.4.0 + espree: 10.3.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.25.1': {} + + '@eslint/object-schema@2.1.6': {} + + '@eslint/plugin-kit@0.2.8': + dependencies: + '@eslint/core': 0.13.0 + levn: 0.4.1 + + '@faker-js/faker@9.7.0': {} + + '@floating-ui/core@1.6.9': + dependencies: + '@floating-ui/utils': 0.2.9 + + '@floating-ui/dom@1.6.13': + dependencies: + '@floating-ui/core': 1.6.9 + '@floating-ui/utils': 0.2.9 + + '@floating-ui/utils@0.2.9': {} + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.6': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.1 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.3.1': {} + + '@humanwhocodes/retry@0.4.2': {} + + '@iconify/json@2.2.331': + dependencies: + '@iconify/types': 2.0.0 + pathe: 1.1.2 + + '@iconify/types@2.0.0': {} + + '@iconify/utils@2.3.0': + dependencies: + '@antfu/install-pkg': 1.0.0 + '@antfu/utils': 8.1.1 + '@iconify/types': 2.0.0 + debug: 4.4.0 + globals: 15.15.0 + kolorist: 1.8.0 + local-pkg: 1.1.1 + mlly: 1.7.4 + transitivePeerDependencies: + - supports-color + + '@iconify/vue@4.2.0(vue@3.5.13(typescript@5.8.3))': + dependencies: + '@iconify/types': 2.0.0 + vue: 3.5.13(typescript@5.8.3) + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@jridgewell/gen-mapping@0.3.8': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@keyv/serialize@1.0.3': + dependencies: + buffer: 6.0.3 + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 + + '@nuxt/kit@3.16.2': + dependencies: + c12: 3.0.3 + consola: 3.4.2 + defu: 6.1.4 + destr: 2.0.5 + errx: 0.1.0 + exsolve: 1.0.5 + globby: 14.1.0 + ignore: 7.0.3 + jiti: 2.4.2 + klona: 2.0.6 + knitwork: 1.2.0 + mlly: 1.7.4 + ohash: 2.0.11 + pathe: 2.0.3 + pkg-types: 2.1.0 + scule: 1.3.0 + semver: 7.7.1 + std-env: 3.9.0 + ufo: 1.6.1 + unctx: 2.4.1 + unimport: 4.2.0 + untyped: 2.0.0 + transitivePeerDependencies: + - magicast + optional: true + + '@parcel/watcher-android-arm64@2.5.1': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.1': + optional: true + + '@parcel/watcher-darwin-x64@2.5.1': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.1': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.1': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.1': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.1': + optional: true + + '@parcel/watcher-win32-arm64@2.5.1': + optional: true + + '@parcel/watcher-win32-ia32@2.5.1': + optional: true + + '@parcel/watcher-win32-x64@2.5.1': + optional: true + + '@parcel/watcher@2.5.1': + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.8 + node-addon-api: 7.1.1 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.1 + '@parcel/watcher-darwin-arm64': 2.5.1 + '@parcel/watcher-darwin-x64': 2.5.1 + '@parcel/watcher-freebsd-x64': 2.5.1 + '@parcel/watcher-linux-arm-glibc': 2.5.1 + '@parcel/watcher-linux-arm-musl': 2.5.1 + '@parcel/watcher-linux-arm64-glibc': 2.5.1 + '@parcel/watcher-linux-arm64-musl': 2.5.1 + '@parcel/watcher-linux-x64-glibc': 2.5.1 + '@parcel/watcher-linux-x64-musl': 2.5.1 + '@parcel/watcher-win32-arm64': 2.5.1 + '@parcel/watcher-win32-ia32': 2.5.1 + '@parcel/watcher-win32-x64': 2.5.1 + optional: true + + '@pkgr/core@0.2.4': {} + + '@popperjs/core@2.11.8': {} + + '@pureadmin/descriptions@1.2.1(echarts@5.6.0)(element-plus@2.9.8(vue@3.5.13(typescript@5.8.3)))(typescript@5.8.3)': + dependencies: + '@element-plus/icons-vue': 2.3.1(vue@3.5.13(typescript@5.8.3)) + '@pureadmin/utils': 2.6.0(echarts@5.6.0)(vue@3.5.13(typescript@5.8.3)) + element-plus: 2.9.8(vue@3.5.13(typescript@5.8.3)) + vue: 3.5.13(typescript@5.8.3) + transitivePeerDependencies: + - echarts + - typescript + + '@pureadmin/table@3.2.1(element-plus@2.9.8(vue@3.5.13(typescript@5.8.3)))(typescript@5.8.3)': + dependencies: + element-plus: 2.9.8(vue@3.5.13(typescript@5.8.3)) + vue: 3.5.13(typescript@5.8.3) + transitivePeerDependencies: + - typescript + + '@pureadmin/utils@2.6.0(echarts@5.6.0)(vue@3.5.13(typescript@5.8.3))': + optionalDependencies: + echarts: 5.6.0 + vue: 3.5.13(typescript@5.8.3) + + '@rollup/pluginutils@5.1.4(rollup@4.40.0)': + dependencies: + '@types/estree': 1.0.7 + estree-walker: 2.0.2 + picomatch: 4.0.2 + optionalDependencies: + rollup: 4.40.0 + + '@rollup/rollup-android-arm-eabi@4.40.0': + optional: true + + '@rollup/rollup-android-arm64@4.40.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.40.0': + optional: true + + '@rollup/rollup-darwin-x64@4.40.0': + optional: true + + '@rollup/rollup-freebsd-arm64@4.40.0': + optional: true + + '@rollup/rollup-freebsd-x64@4.40.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.40.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.40.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.40.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.40.0': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.40.0': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.40.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.40.0': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.40.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.40.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.40.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.40.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.40.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.40.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.40.0': + optional: true + + '@sindresorhus/merge-streams@2.3.0': + optional: true + + '@sxzz/popperjs-es@2.11.7': {} + + '@tailwindcss/node@4.1.4': + dependencies: + enhanced-resolve: 5.18.1 + jiti: 2.4.2 + lightningcss: 1.29.2 + tailwindcss: 4.1.4 + + '@tailwindcss/oxide-android-arm64@4.1.4': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.4': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.4': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.4': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.4': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.4': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.4': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.4': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.4': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.4': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.4': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.4': + optional: true + + '@tailwindcss/oxide@4.1.4': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.4 + '@tailwindcss/oxide-darwin-arm64': 4.1.4 + '@tailwindcss/oxide-darwin-x64': 4.1.4 + '@tailwindcss/oxide-freebsd-x64': 4.1.4 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.4 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.4 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.4 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.4 + '@tailwindcss/oxide-linux-x64-musl': 4.1.4 + '@tailwindcss/oxide-wasm32-wasi': 4.1.4 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.4 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.4 + + '@tailwindcss/vite@4.1.4(vite@6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1))': + dependencies: + '@tailwindcss/node': 4.1.4 + '@tailwindcss/oxide': 4.1.4 + tailwindcss: 4.1.4 + vite: 6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1) + + '@trysound/sax@0.2.0': {} + + '@types/conventional-commits-parser@5.0.1': + dependencies: + '@types/node': 20.17.30 + + '@types/estree@1.0.7': {} + + '@types/js-cookie@3.0.6': {} + + '@types/json-schema@7.0.15': {} + + '@types/lodash-es@4.17.12': + dependencies: + '@types/lodash': 4.17.16 + + '@types/lodash@4.17.16': {} + + '@types/node@20.17.30': + dependencies: + undici-types: 6.19.8 + + '@types/nprogress@0.2.3': {} + + '@types/path-browserify@1.0.3': {} + + '@types/qs@6.9.18': {} + + '@types/sortablejs@1.15.8': {} + + '@types/tinycolor2@1.4.6': {} + + '@types/web-bluetooth@0.0.16': {} + + '@types/web-bluetooth@0.0.21': {} + + '@typescript-eslint/eslint-plugin@8.31.0(@typescript-eslint/parser@8.31.0(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3))(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.31.0(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.31.0 + '@typescript-eslint/type-utils': 8.31.0(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/utils': 8.31.0(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.31.0 + eslint: 9.25.1(jiti@2.4.2) + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.31.0(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.31.0 + '@typescript-eslint/types': 8.31.0 + '@typescript-eslint/typescript-estree': 8.31.0(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.31.0 + debug: 4.4.0 + eslint: 9.25.1(jiti@2.4.2) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.31.0': + dependencies: + '@typescript-eslint/types': 8.31.0 + '@typescript-eslint/visitor-keys': 8.31.0 + + '@typescript-eslint/type-utils@8.31.0(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3)': + dependencies: + '@typescript-eslint/typescript-estree': 8.31.0(typescript@5.8.3) + '@typescript-eslint/utils': 8.31.0(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3) + debug: 4.4.0 + eslint: 9.25.1(jiti@2.4.2) + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.31.0': {} + + '@typescript-eslint/typescript-estree@8.31.0(typescript@5.8.3)': + dependencies: + '@typescript-eslint/types': 8.31.0 + '@typescript-eslint/visitor-keys': 8.31.0 + debug: 4.4.0 + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.1 + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.31.0(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3)': + dependencies: + '@eslint-community/eslint-utils': 4.6.1(eslint@9.25.1(jiti@2.4.2)) + '@typescript-eslint/scope-manager': 8.31.0 + '@typescript-eslint/types': 8.31.0 + '@typescript-eslint/typescript-estree': 8.31.0(typescript@5.8.3) + eslint: 9.25.1(jiti@2.4.2) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.31.0': + dependencies: + '@typescript-eslint/types': 8.31.0 + eslint-visitor-keys: 4.2.0 + + '@vitejs/plugin-vue-jsx@4.1.2(vite@6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1))(vue@3.5.13(typescript@5.8.3))': + dependencies: + '@babel/core': 7.26.10 + '@babel/plugin-transform-typescript': 7.27.0(@babel/core@7.26.10) + '@vue/babel-plugin-jsx': 1.4.0(@babel/core@7.26.10) + vite: 6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1) + vue: 3.5.13(typescript@5.8.3) + transitivePeerDependencies: + - supports-color + + '@vitejs/plugin-vue@5.2.3(vite@6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1))(vue@3.5.13(typescript@5.8.3))': + dependencies: + vite: 6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1) + vue: 3.5.13(typescript@5.8.3) + + '@volar/language-core@2.4.12': + dependencies: + '@volar/source-map': 2.4.12 + + '@volar/source-map@2.4.12': {} + + '@volar/typescript@2.4.12': + dependencies: + '@volar/language-core': 2.4.12 + path-browserify: 1.0.1 + vscode-uri: 3.1.0 + + '@vue/babel-helper-vue-transform-on@1.4.0': {} + + '@vue/babel-plugin-jsx@1.4.0(@babel/core@7.26.10)': + dependencies: + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.10) + '@babel/template': 7.27.0 + '@babel/traverse': 7.27.0 + '@babel/types': 7.27.0 + '@vue/babel-helper-vue-transform-on': 1.4.0 + '@vue/babel-plugin-resolve-type': 1.4.0(@babel/core@7.26.10) + '@vue/shared': 3.5.13 + optionalDependencies: + '@babel/core': 7.26.10 + transitivePeerDependencies: + - supports-color + + '@vue/babel-plugin-resolve-type@1.4.0(@babel/core@7.26.10)': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/core': 7.26.10 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/parser': 7.27.0 + '@vue/compiler-sfc': 3.5.13 + transitivePeerDependencies: + - supports-color + + '@vue/compiler-core@3.5.13': + dependencies: + '@babel/parser': 7.27.0 + '@vue/shared': 3.5.13 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.13': + dependencies: + '@vue/compiler-core': 3.5.13 + '@vue/shared': 3.5.13 + + '@vue/compiler-sfc@3.5.13': + dependencies: + '@babel/parser': 7.27.0 + '@vue/compiler-core': 3.5.13 + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-ssr': 3.5.13 + '@vue/shared': 3.5.13 + estree-walker: 2.0.2 + magic-string: 0.30.17 + postcss: 8.5.3 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.13': + dependencies: + '@vue/compiler-dom': 3.5.13 + '@vue/shared': 3.5.13 + + '@vue/compiler-vue2@2.7.16': + dependencies: + de-indent: 1.0.2 + he: 1.2.0 + + '@vue/devtools-api@6.6.4': {} + + '@vue/devtools-api@7.7.5': + dependencies: + '@vue/devtools-kit': 7.7.5 + + '@vue/devtools-kit@7.7.5': + dependencies: + '@vue/devtools-shared': 7.7.5 + birpc: 2.3.0 + hookable: 5.5.3 + mitt: 3.0.1 + perfect-debounce: 1.0.0 + speakingurl: 14.0.1 + superjson: 2.2.2 + + '@vue/devtools-shared@7.7.5': + dependencies: + rfdc: 1.4.1 + + '@vue/language-core@2.2.10(typescript@5.8.3)': + dependencies: + '@volar/language-core': 2.4.12 + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.5.13 + alien-signals: 1.0.13 + minimatch: 9.0.5 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + optionalDependencies: + typescript: 5.8.3 + + '@vue/reactivity@3.5.13': + dependencies: + '@vue/shared': 3.5.13 + + '@vue/runtime-core@3.5.13': + dependencies: + '@vue/reactivity': 3.5.13 + '@vue/shared': 3.5.13 + + '@vue/runtime-dom@3.5.13': + dependencies: + '@vue/reactivity': 3.5.13 + '@vue/runtime-core': 3.5.13 + '@vue/shared': 3.5.13 + csstype: 3.1.3 + + '@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.3))': + dependencies: + '@vue/compiler-ssr': 3.5.13 + '@vue/shared': 3.5.13 + vue: 3.5.13(typescript@5.8.3) + + '@vue/shared@3.5.13': {} + + '@vueuse/core@13.1.0(vue@3.5.13(typescript@5.8.3))': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 13.1.0 + '@vueuse/shared': 13.1.0(vue@3.5.13(typescript@5.8.3)) + vue: 3.5.13(typescript@5.8.3) + + '@vueuse/core@9.13.0(vue@3.5.13(typescript@5.8.3))': + dependencies: + '@types/web-bluetooth': 0.0.16 + '@vueuse/metadata': 9.13.0 + '@vueuse/shared': 9.13.0(vue@3.5.13(typescript@5.8.3)) + vue-demi: 0.14.10(vue@3.5.13(typescript@5.8.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@vueuse/metadata@13.1.0': {} + + '@vueuse/metadata@9.13.0': {} + + '@vueuse/motion@3.0.3(vue@3.5.13(typescript@5.8.3))': + dependencies: + '@vueuse/core': 13.1.0(vue@3.5.13(typescript@5.8.3)) + '@vueuse/shared': 13.1.0(vue@3.5.13(typescript@5.8.3)) + defu: 6.1.4 + framesync: 6.1.2 + popmotion: 11.0.5 + style-value-types: 5.1.2 + vue: 3.5.13(typescript@5.8.3) + optionalDependencies: + '@nuxt/kit': 3.16.2 + transitivePeerDependencies: + - magicast + + '@vueuse/shared@13.1.0(vue@3.5.13(typescript@5.8.3))': + dependencies: + vue: 3.5.13(typescript@5.8.3) + + '@vueuse/shared@9.13.0(vue@3.5.13(typescript@5.8.3))': + dependencies: + vue-demi: 0.14.10(vue@3.5.13(typescript@5.8.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + JSONStream@1.3.5: + dependencies: + jsonparse: 1.3.1 + through: 2.3.8 + + acorn-jsx@5.3.2(acorn@8.14.1): + dependencies: + acorn: 8.14.1 + + acorn@8.14.1: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.0.6 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + alien-signals@1.0.13: {} + + animate.css@4.1.1: {} + + ansi-align@3.0.1: + dependencies: + string-width: 4.2.3 + + ansi-escapes@7.0.0: + dependencies: + environment: 1.1.0 + + ansi-regex@5.0.1: {} + + ansi-regex@6.1.0: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.1: {} + + argparse@2.0.1: {} + + array-ify@1.0.0: {} + + array-union@2.1.0: {} + + astral-regex@2.0.0: {} + + async-validator@4.2.5: {} + + async@3.2.6: {} + + asynckit@0.4.0: {} + + axios@1.9.0: + dependencies: + follow-redirects: 1.15.9 + form-data: 4.0.2 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + balanced-match@1.0.2: {} + + balanced-match@2.0.0: {} + + base64-js@1.5.1: {} + + birpc@2.3.0: {} + + boolbase@1.0.0: {} + + boxen@8.0.1: + dependencies: + ansi-align: 3.0.1 + camelcase: 8.0.0 + chalk: 5.4.1 + cli-boxes: 3.0.0 + string-width: 7.2.0 + type-fest: 4.40.0 + widest-line: 5.0.0 + wrap-ansi: 9.0.0 + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.24.4: + dependencies: + caniuse-lite: 1.0.30001715 + electron-to-chromium: 1.5.142 + node-releases: 2.0.19 + update-browserslist-db: 1.1.3(browserslist@4.24.4) + + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + bundle-import@0.0.2: + dependencies: + get-tsconfig: 4.10.0 + import-from-string: 0.0.5 + + c12@3.0.3: + dependencies: + chokidar: 4.0.3 + confbox: 0.2.2 + defu: 6.1.4 + dotenv: 16.5.0 + exsolve: 1.0.5 + giget: 2.0.0 + jiti: 2.4.2 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 1.0.0 + pkg-types: 2.1.0 + rc9: 2.1.2 + optional: true + + cacheable@1.8.10: + dependencies: + hookified: 1.8.2 + keyv: 5.3.3 + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + camelcase@8.0.0: {} + + caniuse-api@3.0.0: + dependencies: + browserslist: 4.24.4 + caniuse-lite: 1.0.30001715 + lodash.memoize: 4.1.2 + lodash.uniq: 4.5.0 + + caniuse-lite@1.0.30001715: {} + + chalk@4.1.1: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.4.1: {} + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + citty@0.1.6: + dependencies: + consola: 3.4.2 + optional: true + + cli-boxes@3.0.0: {} + + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + + cli-truncate@4.0.0: + dependencies: + slice-ansi: 5.0.0 + string-width: 7.2.0 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + code-inspector-core@0.20.10: + dependencies: + '@vue/compiler-dom': 3.5.13 + chalk: 4.1.1 + dotenv: 16.5.0 + launch-ide: 1.0.7 + portfinder: 1.0.36 + transitivePeerDependencies: + - supports-color + + code-inspector-plugin@0.20.10: + dependencies: + chalk: 4.1.1 + code-inspector-core: 0.20.10 + dotenv: 16.5.0 + esbuild-code-inspector-plugin: 0.20.10 + vite-code-inspector-plugin: 0.20.10 + webpack-code-inspector-plugin: 0.20.10 + transitivePeerDependencies: + - supports-color + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + colord@2.9.3: {} + + colorette@2.0.20: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@13.1.0: {} + + commander@7.2.0: {} + + compare-func@2.0.0: + dependencies: + array-ify: 1.0.0 + dot-prop: 5.3.0 + + concat-map@0.0.1: {} + + confbox@0.1.8: {} + + confbox@0.2.2: {} + + consola@3.4.2: + optional: true + + conventional-changelog-angular@7.0.0: + dependencies: + compare-func: 2.0.0 + + conventional-changelog-conventionalcommits@7.0.2: + dependencies: + compare-func: 2.0.0 + + conventional-commits-parser@5.0.0: + dependencies: + JSONStream: 1.3.5 + is-text-path: 2.0.0 + meow: 12.1.1 + split2: 4.2.0 + + convert-source-map@2.0.0: {} + + copy-anything@3.0.5: + dependencies: + is-what: 4.1.16 + + cosmiconfig-typescript-loader@6.1.0(@types/node@20.17.30)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3): + dependencies: + '@types/node': 20.17.30 + cosmiconfig: 9.0.0(typescript@5.8.3) + jiti: 2.4.2 + typescript: 5.8.3 + + cosmiconfig@9.0.0(typescript@5.8.3): + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + parse-json: 5.2.0 + optionalDependencies: + typescript: 5.8.3 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + css-declaration-sorter@7.2.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + + css-functions-list@3.2.3: {} + + css-select@5.1.0: + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-tree@2.2.1: + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.2.1 + + css-tree@2.3.1: + dependencies: + mdn-data: 2.0.30 + source-map-js: 1.2.1 + + css-tree@3.1.0: + dependencies: + mdn-data: 2.12.2 + source-map-js: 1.2.1 + + css-what@6.1.0: {} + + cssesc@3.0.0: {} + + cssnano-preset-default@7.0.6(postcss@8.5.3): + dependencies: + browserslist: 4.24.4 + css-declaration-sorter: 7.2.0(postcss@8.5.3) + cssnano-utils: 5.0.0(postcss@8.5.3) + postcss: 8.5.3 + postcss-calc: 10.1.1(postcss@8.5.3) + postcss-colormin: 7.0.2(postcss@8.5.3) + postcss-convert-values: 7.0.4(postcss@8.5.3) + postcss-discard-comments: 7.0.3(postcss@8.5.3) + postcss-discard-duplicates: 7.0.1(postcss@8.5.3) + postcss-discard-empty: 7.0.0(postcss@8.5.3) + postcss-discard-overridden: 7.0.0(postcss@8.5.3) + postcss-merge-longhand: 7.0.4(postcss@8.5.3) + postcss-merge-rules: 7.0.4(postcss@8.5.3) + postcss-minify-font-values: 7.0.0(postcss@8.5.3) + postcss-minify-gradients: 7.0.0(postcss@8.5.3) + postcss-minify-params: 7.0.2(postcss@8.5.3) + postcss-minify-selectors: 7.0.4(postcss@8.5.3) + postcss-normalize-charset: 7.0.0(postcss@8.5.3) + postcss-normalize-display-values: 7.0.0(postcss@8.5.3) + postcss-normalize-positions: 7.0.0(postcss@8.5.3) + postcss-normalize-repeat-style: 7.0.0(postcss@8.5.3) + postcss-normalize-string: 7.0.0(postcss@8.5.3) + postcss-normalize-timing-functions: 7.0.0(postcss@8.5.3) + postcss-normalize-unicode: 7.0.2(postcss@8.5.3) + postcss-normalize-url: 7.0.0(postcss@8.5.3) + postcss-normalize-whitespace: 7.0.0(postcss@8.5.3) + postcss-ordered-values: 7.0.1(postcss@8.5.3) + postcss-reduce-initial: 7.0.2(postcss@8.5.3) + postcss-reduce-transforms: 7.0.0(postcss@8.5.3) + postcss-svgo: 7.0.1(postcss@8.5.3) + postcss-unique-selectors: 7.0.3(postcss@8.5.3) + + cssnano-utils@5.0.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + + cssnano@7.0.6(postcss@8.5.3): + dependencies: + cssnano-preset-default: 7.0.6(postcss@8.5.3) + lilconfig: 3.1.3 + postcss: 8.5.3 + + csso@5.0.5: + dependencies: + css-tree: 2.2.1 + + csstype@3.1.3: {} + + dargs@8.1.0: {} + + dayjs@1.11.13: {} + + de-indent@1.0.2: {} + + debug@4.4.0: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + define-lazy-prop@2.0.0: {} + + defu@6.1.4: {} + + delayed-stream@1.0.0: {} + + destr@2.0.5: + optional: true + + detect-libc@1.0.3: + optional: true + + detect-libc@2.0.4: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dot-prop@5.3.0: + dependencies: + is-obj: 2.0.0 + + dotenv@16.5.0: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + echarts@5.6.0: + dependencies: + tslib: 2.3.0 + zrender: 5.6.1 + + electron-to-chromium@1.5.142: {} + + element-plus@2.9.8(vue@3.5.13(typescript@5.8.3)): + dependencies: + '@ctrl/tinycolor': 3.6.1 + '@element-plus/icons-vue': 2.3.1(vue@3.5.13(typescript@5.8.3)) + '@floating-ui/dom': 1.6.13 + '@popperjs/core': '@sxzz/popperjs-es@2.11.7' + '@types/lodash': 4.17.16 + '@types/lodash-es': 4.17.12 + '@vueuse/core': 9.13.0(vue@3.5.13(typescript@5.8.3)) + async-validator: 4.2.5 + dayjs: 1.11.13 + escape-html: 1.0.3 + lodash: 4.17.21 + lodash-es: 4.17.21 + lodash-unified: 1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21) + memoize-one: 6.0.0 + normalize-wheel-es: 1.2.0 + vue: 3.5.13(typescript@5.8.3) + transitivePeerDependencies: + - '@vue/composition-api' + + emoji-regex@10.4.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + enhanced-resolve@5.18.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + + entities@4.5.0: {} + + env-paths@2.2.1: {} + + environment@1.1.0: {} + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + + errx@0.1.0: + optional: true + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@0.4.1: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + esbuild-code-inspector-plugin@0.20.10: + dependencies: + code-inspector-core: 0.20.10 + transitivePeerDependencies: + - supports-color + + esbuild@0.24.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.24.2 + '@esbuild/android-arm': 0.24.2 + '@esbuild/android-arm64': 0.24.2 + '@esbuild/android-x64': 0.24.2 + '@esbuild/darwin-arm64': 0.24.2 + '@esbuild/darwin-x64': 0.24.2 + '@esbuild/freebsd-arm64': 0.24.2 + '@esbuild/freebsd-x64': 0.24.2 + '@esbuild/linux-arm': 0.24.2 + '@esbuild/linux-arm64': 0.24.2 + '@esbuild/linux-ia32': 0.24.2 + '@esbuild/linux-loong64': 0.24.2 + '@esbuild/linux-mips64el': 0.24.2 + '@esbuild/linux-ppc64': 0.24.2 + '@esbuild/linux-riscv64': 0.24.2 + '@esbuild/linux-s390x': 0.24.2 + '@esbuild/linux-x64': 0.24.2 + '@esbuild/netbsd-arm64': 0.24.2 + '@esbuild/netbsd-x64': 0.24.2 + '@esbuild/openbsd-arm64': 0.24.2 + '@esbuild/openbsd-x64': 0.24.2 + '@esbuild/sunos-x64': 0.24.2 + '@esbuild/win32-arm64': 0.24.2 + '@esbuild/win32-ia32': 0.24.2 + '@esbuild/win32-x64': 0.24.2 + + esbuild@0.25.3: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.3 + '@esbuild/android-arm': 0.25.3 + '@esbuild/android-arm64': 0.25.3 + '@esbuild/android-x64': 0.25.3 + '@esbuild/darwin-arm64': 0.25.3 + '@esbuild/darwin-x64': 0.25.3 + '@esbuild/freebsd-arm64': 0.25.3 + '@esbuild/freebsd-x64': 0.25.3 + '@esbuild/linux-arm': 0.25.3 + '@esbuild/linux-arm64': 0.25.3 + '@esbuild/linux-ia32': 0.25.3 + '@esbuild/linux-loong64': 0.25.3 + '@esbuild/linux-mips64el': 0.25.3 + '@esbuild/linux-ppc64': 0.25.3 + '@esbuild/linux-riscv64': 0.25.3 + '@esbuild/linux-s390x': 0.25.3 + '@esbuild/linux-x64': 0.25.3 + '@esbuild/netbsd-arm64': 0.25.3 + '@esbuild/netbsd-x64': 0.25.3 + '@esbuild/openbsd-arm64': 0.25.3 + '@esbuild/openbsd-x64': 0.25.3 + '@esbuild/sunos-x64': 0.25.3 + '@esbuild/win32-arm64': 0.25.3 + '@esbuild/win32-ia32': 0.25.3 + '@esbuild/win32-x64': 0.25.3 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + escape-string-regexp@4.0.0: {} + + escape-string-regexp@5.0.0: + optional: true + + eslint-config-prettier@10.1.2(eslint@9.25.1(jiti@2.4.2)): + dependencies: + eslint: 9.25.1(jiti@2.4.2) + + eslint-plugin-prettier@5.2.6(eslint-config-prettier@10.1.2(eslint@9.25.1(jiti@2.4.2)))(eslint@9.25.1(jiti@2.4.2))(prettier@3.5.3): + dependencies: + eslint: 9.25.1(jiti@2.4.2) + prettier: 3.5.3 + prettier-linter-helpers: 1.0.0 + synckit: 0.11.4 + optionalDependencies: + eslint-config-prettier: 10.1.2(eslint@9.25.1(jiti@2.4.2)) + + eslint-plugin-vue@10.0.0(eslint@9.25.1(jiti@2.4.2))(vue-eslint-parser@10.1.3(eslint@9.25.1(jiti@2.4.2))): + dependencies: + '@eslint-community/eslint-utils': 4.6.1(eslint@9.25.1(jiti@2.4.2)) + eslint: 9.25.1(jiti@2.4.2) + natural-compare: 1.4.0 + nth-check: 2.1.1 + postcss-selector-parser: 6.1.2 + semver: 7.7.1 + vue-eslint-parser: 10.1.3(eslint@9.25.1(jiti@2.4.2)) + xml-name-validator: 4.0.0 + + eslint-scope@8.3.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.0: {} + + eslint@9.25.1(jiti@2.4.2): + dependencies: + '@eslint-community/eslint-utils': 4.6.1(eslint@9.25.1(jiti@2.4.2)) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.20.0 + '@eslint/config-helpers': 0.2.1 + '@eslint/core': 0.13.0 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.25.1 + '@eslint/plugin-kit': 0.2.8 + '@humanfs/node': 0.16.6 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.2 + '@types/estree': 1.0.7 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.0 + escape-string-regexp: 4.0.0 + eslint-scope: 8.3.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.4.2 + transitivePeerDependencies: + - supports-color + + espree@10.3.0: + dependencies: + acorn: 8.14.1 + acorn-jsx: 5.3.2(acorn@8.14.1) + eslint-visitor-keys: 4.2.0 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.7 + + esutils@2.0.3: {} + + eventemitter3@5.0.1: {} + + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + exsolve@1.0.5: {} + + fast-deep-equal@3.1.3: {} + + fast-diff@1.3.0: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-uri@3.0.6: {} + + fastest-levenshtein@1.0.16: {} + + fastq@1.19.1: + dependencies: + reusify: 1.1.0 + + fdir@6.4.4(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + + file-entry-cache@10.0.8: + dependencies: + flat-cache: 6.1.8 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + find-up@7.0.0: + dependencies: + locate-path: 7.2.0 + path-exists: 5.0.0 + unicorn-magic: 0.1.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flat-cache@6.1.8: + dependencies: + cacheable: 1.8.10 + flatted: 3.3.3 + hookified: 1.8.2 + + flatted@3.3.3: {} + + follow-redirects@1.15.9: {} + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + form-data@4.0.2: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + mime-types: 2.1.35 + + framesync@6.1.2: + dependencies: + tslib: 2.4.0 + + fs-extra@10.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-east-asian-width@1.3.0: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-stream@8.0.1: {} + + get-tsconfig@4.10.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + giget@2.0.0: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + defu: 6.1.4 + node-fetch-native: 1.6.6 + nypm: 0.6.0 + pathe: 2.0.3 + optional: true + + git-raw-commits@4.0.0: + dependencies: + dargs: 8.1.0 + meow: 12.1.1 + split2: 4.2.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@11.0.2: + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.1.0 + minimatch: 10.0.1 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 + + global-directory@4.0.1: + dependencies: + ini: 4.1.1 + + global-modules@2.0.0: + dependencies: + global-prefix: 3.0.0 + + global-prefix@3.0.0: + dependencies: + ini: 1.3.8 + kind-of: 6.0.3 + which: 1.3.1 + + globals@11.12.0: {} + + globals@14.0.0: {} + + globals@15.15.0: {} + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + globby@14.1.0: + dependencies: + '@sindresorhus/merge-streams': 2.3.0 + fast-glob: 3.3.3 + ignore: 7.0.3 + path-type: 6.0.0 + slash: 5.1.0 + unicorn-magic: 0.3.0 + optional: true + + globjoin@0.1.4: {} + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + gradient-string@3.0.0: + dependencies: + chalk: 5.4.1 + tinygradient: 1.1.5 + + graphemer@1.4.0: {} + + has-flag@4.0.0: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + he@1.2.0: {} + + hey-listen@1.0.8: {} + + hookable@5.5.3: {} + + hookified@1.8.2: {} + + html-tags@3.3.1: {} + + htmlparser2@8.0.2: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 4.5.0 + + human-signals@5.0.0: {} + + husky@9.1.7: {} + + ieee754@1.2.1: {} + + ignore@5.3.2: {} + + ignore@7.0.3: {} + + immediate@3.0.6: {} + + immutable@5.1.1: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + import-from-string@0.0.5: + dependencies: + esbuild: 0.24.2 + import-meta-resolve: 4.1.0 + + import-meta-resolve@4.1.0: {} + + imurmurhash@0.1.4: {} + + ini@1.3.8: {} + + ini@4.1.1: {} + + is-arrayish@0.2.1: {} + + is-docker@2.2.1: {} + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-fullwidth-code-point@4.0.0: {} + + is-fullwidth-code-point@5.0.0: + dependencies: + get-east-asian-width: 1.3.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-obj@2.0.0: {} + + is-plain-object@5.0.0: {} + + is-reference@3.0.3: + dependencies: + '@types/estree': 1.0.7 + + is-stream@3.0.0: {} + + is-text-path@2.0.0: + dependencies: + text-extensions: 2.4.0 + + is-what@4.1.16: {} + + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + + isexe@2.0.0: {} + + jackspeak@4.1.0: + dependencies: + '@isaacs/cliui': 8.0.2 + + jiti@2.4.2: {} + + js-cookie@3.0.5: {} + + js-tokens@4.0.0: {} + + js-tokens@9.0.1: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@2.2.3: {} + + jsonfile@6.1.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + jsonparse@1.3.1: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + keyv@5.3.3: + dependencies: + '@keyv/serialize': 1.0.3 + + kind-of@6.0.3: {} + + klona@2.0.6: + optional: true + + knitwork@1.2.0: + optional: true + + known-css-properties@0.35.0: {} + + known-css-properties@0.36.0: {} + + kolorist@1.8.0: {} + + launch-ide@1.0.7: + dependencies: + chalk: 4.1.1 + dotenv: 16.5.0 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lie@3.1.1: + dependencies: + immediate: 3.0.6 + + lightningcss-darwin-arm64@1.29.2: + optional: true + + lightningcss-darwin-x64@1.29.2: + optional: true + + lightningcss-freebsd-x64@1.29.2: + optional: true + + lightningcss-linux-arm-gnueabihf@1.29.2: + optional: true + + lightningcss-linux-arm64-gnu@1.29.2: + optional: true + + lightningcss-linux-arm64-musl@1.29.2: + optional: true + + lightningcss-linux-x64-gnu@1.29.2: + optional: true + + lightningcss-linux-x64-musl@1.29.2: + optional: true + + lightningcss-win32-arm64-msvc@1.29.2: + optional: true + + lightningcss-win32-x64-msvc@1.29.2: + optional: true + + lightningcss@1.29.2: + dependencies: + detect-libc: 2.0.4 + optionalDependencies: + lightningcss-darwin-arm64: 1.29.2 + lightningcss-darwin-x64: 1.29.2 + lightningcss-freebsd-x64: 1.29.2 + lightningcss-linux-arm-gnueabihf: 1.29.2 + lightningcss-linux-arm64-gnu: 1.29.2 + lightningcss-linux-arm64-musl: 1.29.2 + lightningcss-linux-x64-gnu: 1.29.2 + lightningcss-linux-x64-musl: 1.29.2 + lightningcss-win32-arm64-msvc: 1.29.2 + lightningcss-win32-x64-msvc: 1.29.2 + + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + + lint-staged@15.5.1: + dependencies: + chalk: 5.4.1 + commander: 13.1.0 + debug: 4.4.0 + execa: 8.0.1 + lilconfig: 3.1.3 + listr2: 8.3.2 + micromatch: 4.0.8 + pidtree: 0.6.0 + string-argv: 0.3.2 + yaml: 2.7.1 + transitivePeerDependencies: + - supports-color + + listr2@8.3.2: + dependencies: + cli-truncate: 4.0.0 + colorette: 2.0.20 + eventemitter3: 5.0.1 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 9.0.0 + + local-pkg@1.1.1: + dependencies: + mlly: 1.7.4 + pkg-types: 2.1.0 + quansync: 0.2.10 + + localforage@1.10.0: + dependencies: + lie: 3.1.1 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + locate-path@7.2.0: + dependencies: + p-locate: 6.0.0 + + lodash-es@4.17.21: {} + + lodash-unified@1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21): + dependencies: + '@types/lodash-es': 4.17.12 + lodash: 4.17.21 + lodash-es: 4.17.21 + + lodash.camelcase@4.3.0: {} + + lodash.isplainobject@4.0.6: {} + + lodash.kebabcase@4.1.1: {} + + lodash.memoize@4.1.2: {} + + lodash.merge@4.6.2: {} + + lodash.mergewith@4.6.2: {} + + lodash.snakecase@4.1.1: {} + + lodash.startcase@4.4.0: {} + + lodash.truncate@4.4.2: {} + + lodash.uniq@4.5.0: {} + + lodash.upperfirst@4.3.1: {} + + lodash@4.17.21: {} + + log-update@6.1.0: + dependencies: + ansi-escapes: 7.0.0 + cli-cursor: 5.0.0 + slice-ansi: 7.1.0 + strip-ansi: 7.1.0 + wrap-ansi: 9.0.0 + + lru-cache@11.1.0: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + magic-string@0.25.9: + dependencies: + sourcemap-codec: 1.4.8 + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + math-intrinsics@1.1.0: {} + + mathml-tag-names@2.1.3: {} + + mdn-data@2.0.28: {} + + mdn-data@2.0.30: {} + + mdn-data@2.12.2: {} + + mdn-data@2.21.0: {} + + memoize-one@6.0.0: {} + + meow@12.1.1: {} + + meow@13.2.0: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mimic-fn@4.0.0: {} + + mimic-function@5.0.1: {} + + minimatch@10.0.1: + dependencies: + brace-expansion: 2.0.1 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + minimist@1.2.8: {} + + minipass@7.1.2: {} + + mitt@3.0.1: {} + + mlly@1.7.4: + dependencies: + acorn: 8.14.1 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.1 + + ms@2.1.3: {} + + muggle-string@0.4.1: {} + + nanoid@3.3.11: {} + + natural-compare@1.4.0: {} + + node-addon-api@7.1.1: + optional: true + + node-fetch-native@1.6.6: + optional: true + + node-releases@2.0.19: {} + + normalize-path@3.0.0: {} + + normalize-wheel-es@1.2.0: {} + + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + nprogress@0.2.0: {} + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + nypm@0.6.0: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + pathe: 2.0.3 + pkg-types: 2.1.0 + tinyexec: 0.3.2 + optional: true + + object-inspect@1.13.4: {} + + ohash@2.0.11: + optional: true + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + + open@8.4.2: + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-limit@4.0.0: + dependencies: + yocto-queue: 1.2.1 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-locate@6.0.0: + dependencies: + p-limit: 4.0.0 + + package-json-from-dist@1.0.1: {} + + package-manager-detector@0.2.11: + dependencies: + quansync: 0.2.10 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.26.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + path-browserify@1.0.1: {} + + path-exists@4.0.0: {} + + path-exists@5.0.0: {} + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + path-scurry@2.0.0: + dependencies: + lru-cache: 11.1.0 + minipass: 7.1.2 + + path-to-regexp@8.2.0: {} + + path-type@4.0.0: {} + + path-type@6.0.0: + optional: true + + pathe@1.1.2: {} + + pathe@2.0.3: {} + + perfect-debounce@1.0.0: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.2: {} + + pidtree@0.6.0: {} + + pinia@3.0.2(typescript@5.8.3)(vue@3.5.13(typescript@5.8.3)): + dependencies: + '@vue/devtools-api': 7.7.5 + vue: 3.5.13(typescript@5.8.3) + optionalDependencies: + typescript: 5.8.3 + + pinyin-pro@3.26.0: {} + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.7.4 + pathe: 2.0.3 + + pkg-types@2.1.0: + dependencies: + confbox: 0.2.2 + exsolve: 1.0.5 + pathe: 2.0.3 + + popmotion@11.0.5: + dependencies: + framesync: 6.1.2 + hey-listen: 1.0.8 + style-value-types: 5.1.2 + tslib: 2.4.0 + + portfinder@1.0.36: + dependencies: + async: 3.2.6 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + postcss-calc@10.1.1(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-selector-parser: 7.1.0 + postcss-value-parser: 4.2.0 + + postcss-colormin@7.0.2(postcss@8.5.3): + dependencies: + browserslist: 4.24.4 + caniuse-api: 3.0.0 + colord: 2.9.3 + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + + postcss-convert-values@7.0.4(postcss@8.5.3): + dependencies: + browserslist: 4.24.4 + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + + postcss-discard-comments@7.0.3(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-selector-parser: 6.1.2 + + postcss-discard-duplicates@7.0.1(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + + postcss-discard-empty@7.0.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + + postcss-discard-overridden@7.0.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + + postcss-html@1.8.0: + dependencies: + htmlparser2: 8.0.2 + js-tokens: 9.0.1 + postcss: 8.5.3 + postcss-safe-parser: 6.0.0(postcss@8.5.3) + + postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(yaml@2.7.1): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + jiti: 2.4.2 + postcss: 8.5.3 + yaml: 2.7.1 + + postcss-media-query-parser@0.2.3: {} + + postcss-merge-longhand@7.0.4(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + stylehacks: 7.0.4(postcss@8.5.3) + + postcss-merge-rules@7.0.4(postcss@8.5.3): + dependencies: + browserslist: 4.24.4 + caniuse-api: 3.0.0 + cssnano-utils: 5.0.0(postcss@8.5.3) + postcss: 8.5.3 + postcss-selector-parser: 6.1.2 + + postcss-minify-font-values@7.0.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + + postcss-minify-gradients@7.0.0(postcss@8.5.3): + dependencies: + colord: 2.9.3 + cssnano-utils: 5.0.0(postcss@8.5.3) + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + + postcss-minify-params@7.0.2(postcss@8.5.3): + dependencies: + browserslist: 4.24.4 + cssnano-utils: 5.0.0(postcss@8.5.3) + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + + postcss-minify-selectors@7.0.4(postcss@8.5.3): + dependencies: + cssesc: 3.0.0 + postcss: 8.5.3 + postcss-selector-parser: 6.1.2 + + postcss-normalize-charset@7.0.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + + postcss-normalize-display-values@7.0.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + + postcss-normalize-positions@7.0.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + + postcss-normalize-repeat-style@7.0.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + + postcss-normalize-string@7.0.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + + postcss-normalize-timing-functions@7.0.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + + postcss-normalize-unicode@7.0.2(postcss@8.5.3): + dependencies: + browserslist: 4.24.4 + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + + postcss-normalize-url@7.0.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + + postcss-normalize-whitespace@7.0.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + + postcss-ordered-values@7.0.1(postcss@8.5.3): + dependencies: + cssnano-utils: 5.0.0(postcss@8.5.3) + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + + postcss-reduce-initial@7.0.2(postcss@8.5.3): + dependencies: + browserslist: 4.24.4 + caniuse-api: 3.0.0 + postcss: 8.5.3 + + postcss-reduce-transforms@7.0.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + + postcss-resolve-nested-selector@0.1.6: {} + + postcss-safe-parser@6.0.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + + postcss-safe-parser@7.0.1(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + + postcss-scss@4.0.9(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-selector-parser@7.1.0: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-sorting@8.0.2(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + + postcss-svgo@7.0.1(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + svgo: 3.3.2 + + postcss-unique-selectors@7.0.3(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-selector-parser: 6.1.2 + + postcss-value-parser@4.2.0: {} + + postcss@8.5.3: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.3.0 + + prettier@3.5.3: {} + + proxy-from-env@1.1.0: {} + + punycode@2.3.1: {} + + qs@6.14.0: + dependencies: + side-channel: 1.1.0 + + quansync@0.2.10: {} + + queue-microtask@1.2.3: {} + + rc9@2.1.2: + dependencies: + defu: 6.1.4 + destr: 2.0.5 + optional: true + + readdirp@4.1.2: {} + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + responsive-storage@2.2.0: {} + + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + + reusify@1.1.0: {} + + rfdc@1.4.1: {} + + rimraf@6.0.1: + dependencies: + glob: 11.0.2 + package-json-from-dist: 1.0.1 + + rollup-plugin-external-globals@0.10.0(rollup@4.40.0): + dependencies: + '@rollup/pluginutils': 5.1.4(rollup@4.40.0) + estree-walker: 3.0.3 + is-reference: 3.0.3 + magic-string: 0.30.17 + rollup: 4.40.0 + + rollup-plugin-visualizer@5.14.0(rollup@4.40.0): + dependencies: + open: 8.4.2 + picomatch: 4.0.2 + source-map: 0.7.4 + yargs: 17.7.2 + optionalDependencies: + rollup: 4.40.0 + + rollup@4.40.0: + dependencies: + '@types/estree': 1.0.7 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.40.0 + '@rollup/rollup-android-arm64': 4.40.0 + '@rollup/rollup-darwin-arm64': 4.40.0 + '@rollup/rollup-darwin-x64': 4.40.0 + '@rollup/rollup-freebsd-arm64': 4.40.0 + '@rollup/rollup-freebsd-x64': 4.40.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.40.0 + '@rollup/rollup-linux-arm-musleabihf': 4.40.0 + '@rollup/rollup-linux-arm64-gnu': 4.40.0 + '@rollup/rollup-linux-arm64-musl': 4.40.0 + '@rollup/rollup-linux-loongarch64-gnu': 4.40.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.40.0 + '@rollup/rollup-linux-riscv64-gnu': 4.40.0 + '@rollup/rollup-linux-riscv64-musl': 4.40.0 + '@rollup/rollup-linux-s390x-gnu': 4.40.0 + '@rollup/rollup-linux-x64-gnu': 4.40.0 + '@rollup/rollup-linux-x64-musl': 4.40.0 + '@rollup/rollup-win32-arm64-msvc': 4.40.0 + '@rollup/rollup-win32-ia32-msvc': 4.40.0 + '@rollup/rollup-win32-x64-msvc': 4.40.0 + fsevents: 2.3.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + sass@1.87.0: + dependencies: + chokidar: 4.0.3 + immutable: 5.1.1 + source-map-js: 1.2.1 + optionalDependencies: + '@parcel/watcher': 2.5.1 + + scule@1.3.0: + optional: true + + semver@6.3.1: {} + + semver@7.7.1: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + signal-exit@4.1.0: {} + + slash@3.0.0: {} + + slash@5.1.0: + optional: true + + slice-ansi@4.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + + slice-ansi@5.0.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + + slice-ansi@7.1.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 5.0.0 + + sortablejs@1.15.6: {} + + source-map-js@1.2.1: {} + + source-map@0.7.4: {} + + sourcemap-codec@1.4.8: {} + + speakingurl@14.0.1: {} + + split2@4.2.0: {} + + std-env@3.9.0: + optional: true + + string-argv@0.3.2: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + string-width@7.2.0: + dependencies: + emoji-regex: 10.4.0 + get-east-asian-width: 1.3.0 + strip-ansi: 7.1.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.1.0 + + strip-final-newline@3.0.0: {} + + strip-json-comments@3.1.1: {} + + strip-literal@3.0.0: + dependencies: + js-tokens: 9.0.1 + optional: true + + style-value-types@5.1.2: + dependencies: + hey-listen: 1.0.8 + tslib: 2.4.0 + + stylehacks@7.0.4(postcss@8.5.3): + dependencies: + browserslist: 4.24.4 + postcss: 8.5.3 + postcss-selector-parser: 6.1.2 + + stylelint-config-html@1.1.0(postcss-html@1.8.0)(stylelint@16.19.0(typescript@5.8.3)): + dependencies: + postcss-html: 1.8.0 + stylelint: 16.19.0(typescript@5.8.3) + + stylelint-config-recess-order@6.0.0(stylelint@16.19.0(typescript@5.8.3)): + dependencies: + stylelint: 16.19.0(typescript@5.8.3) + stylelint-order: 6.0.4(stylelint@16.19.0(typescript@5.8.3)) + + stylelint-config-recommended-scss@14.1.0(postcss@8.5.3)(stylelint@16.19.0(typescript@5.8.3)): + dependencies: + postcss-scss: 4.0.9(postcss@8.5.3) + stylelint: 16.19.0(typescript@5.8.3) + stylelint-config-recommended: 14.0.1(stylelint@16.19.0(typescript@5.8.3)) + stylelint-scss: 6.11.1(stylelint@16.19.0(typescript@5.8.3)) + optionalDependencies: + postcss: 8.5.3 + + stylelint-config-recommended-vue@1.6.0(postcss-html@1.8.0)(stylelint@16.19.0(typescript@5.8.3)): + dependencies: + postcss-html: 1.8.0 + semver: 7.7.1 + stylelint: 16.19.0(typescript@5.8.3) + stylelint-config-html: 1.1.0(postcss-html@1.8.0)(stylelint@16.19.0(typescript@5.8.3)) + stylelint-config-recommended: 16.0.0(stylelint@16.19.0(typescript@5.8.3)) + + stylelint-config-recommended@14.0.1(stylelint@16.19.0(typescript@5.8.3)): + dependencies: + stylelint: 16.19.0(typescript@5.8.3) + + stylelint-config-recommended@16.0.0(stylelint@16.19.0(typescript@5.8.3)): + dependencies: + stylelint: 16.19.0(typescript@5.8.3) + + stylelint-config-standard-scss@14.0.0(postcss@8.5.3)(stylelint@16.19.0(typescript@5.8.3)): + dependencies: + stylelint: 16.19.0(typescript@5.8.3) + stylelint-config-recommended-scss: 14.1.0(postcss@8.5.3)(stylelint@16.19.0(typescript@5.8.3)) + stylelint-config-standard: 36.0.1(stylelint@16.19.0(typescript@5.8.3)) + optionalDependencies: + postcss: 8.5.3 + + stylelint-config-standard@36.0.1(stylelint@16.19.0(typescript@5.8.3)): + dependencies: + stylelint: 16.19.0(typescript@5.8.3) + stylelint-config-recommended: 14.0.1(stylelint@16.19.0(typescript@5.8.3)) + + stylelint-order@6.0.4(stylelint@16.19.0(typescript@5.8.3)): + dependencies: + postcss: 8.5.3 + postcss-sorting: 8.0.2(postcss@8.5.3) + stylelint: 16.19.0(typescript@5.8.3) + + stylelint-prettier@5.0.3(prettier@3.5.3)(stylelint@16.19.0(typescript@5.8.3)): + dependencies: + prettier: 3.5.3 + prettier-linter-helpers: 1.0.0 + stylelint: 16.19.0(typescript@5.8.3) + + stylelint-scss@6.11.1(stylelint@16.19.0(typescript@5.8.3)): + dependencies: + css-tree: 3.1.0 + is-plain-object: 5.0.0 + known-css-properties: 0.35.0 + mdn-data: 2.21.0 + postcss-media-query-parser: 0.2.3 + postcss-resolve-nested-selector: 0.1.6 + postcss-selector-parser: 7.1.0 + postcss-value-parser: 4.2.0 + stylelint: 16.19.0(typescript@5.8.3) + + stylelint@16.19.0(typescript@5.8.3): + dependencies: + '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3) + '@csstools/css-tokenizer': 3.0.3 + '@csstools/media-query-list-parser': 4.0.2(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3) + '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.0) + '@dual-bundle/import-meta-resolve': 4.1.0 + balanced-match: 2.0.0 + colord: 2.9.3 + cosmiconfig: 9.0.0(typescript@5.8.3) + css-functions-list: 3.2.3 + css-tree: 3.1.0 + debug: 4.4.0 + fast-glob: 3.3.3 + fastest-levenshtein: 1.0.16 + file-entry-cache: 10.0.8 + global-modules: 2.0.0 + globby: 11.1.0 + globjoin: 0.1.4 + html-tags: 3.3.1 + ignore: 7.0.3 + imurmurhash: 0.1.4 + is-plain-object: 5.0.0 + known-css-properties: 0.36.0 + mathml-tag-names: 2.1.3 + meow: 13.2.0 + micromatch: 4.0.8 + normalize-path: 3.0.0 + picocolors: 1.1.1 + postcss: 8.5.3 + postcss-resolve-nested-selector: 0.1.6 + postcss-safe-parser: 7.0.1(postcss@8.5.3) + postcss-selector-parser: 7.1.0 + postcss-value-parser: 4.2.0 + resolve-from: 5.0.0 + string-width: 4.2.3 + supports-hyperlinks: 3.2.0 + svg-tags: 1.0.0 + table: 6.9.0 + write-file-atomic: 5.0.1 + transitivePeerDependencies: + - supports-color + - typescript + + superjson@2.2.2: + dependencies: + copy-anything: 3.0.5 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-hyperlinks@3.2.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + + svg-tags@1.0.0: {} + + svgo@3.3.2: + dependencies: + '@trysound/sax': 0.2.0 + commander: 7.2.0 + css-select: 5.1.0 + css-tree: 2.3.1 + css-what: 6.1.0 + csso: 5.0.5 + picocolors: 1.1.1 + + synckit@0.11.4: + dependencies: + '@pkgr/core': 0.2.4 + tslib: 2.8.1 + + table@6.9.0: + dependencies: + ajv: 8.17.1 + lodash.truncate: 4.4.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + tailwindcss@4.1.4: {} + + tapable@2.2.1: {} + + text-extensions@2.4.0: {} + + through@2.3.8: {} + + tinycolor2@1.6.0: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.13: + dependencies: + fdir: 6.4.4(picomatch@4.0.2) + picomatch: 4.0.2 + + tinygradient@1.1.5: + dependencies: + '@types/tinycolor2': 1.4.6 + tinycolor2: 1.6.0 + + tippy.js@6.3.7: + dependencies: + '@popperjs/core': 2.11.8 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-api-utils@2.1.0(typescript@5.8.3): + dependencies: + typescript: 5.8.3 + + tslib@2.3.0: {} + + tslib@2.4.0: {} + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-fest@4.40.0: {} + + typescript-eslint@8.31.0(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.31.0(@typescript-eslint/parser@8.31.0(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3))(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/parser': 8.31.0(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/utils': 8.31.0(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3) + eslint: 9.25.1(jiti@2.4.2) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + typescript@5.8.3: {} + + ufo@1.6.1: {} + + unctx@2.4.1: + dependencies: + acorn: 8.14.1 + estree-walker: 3.0.3 + magic-string: 0.30.17 + unplugin: 2.3.2 + optional: true + + undici-types@6.19.8: {} + + unicorn-magic@0.1.0: {} + + unicorn-magic@0.3.0: + optional: true + + unimport@4.2.0: + dependencies: + acorn: 8.14.1 + escape-string-regexp: 5.0.0 + estree-walker: 3.0.3 + local-pkg: 1.1.1 + magic-string: 0.30.17 + mlly: 1.7.4 + pathe: 2.0.3 + picomatch: 4.0.2 + pkg-types: 2.1.0 + scule: 1.3.0 + strip-literal: 3.0.0 + tinyglobby: 0.2.13 + unplugin: 2.3.2 + unplugin-utils: 0.2.4 + optional: true + + universalify@2.0.1: {} + + unplugin-icons@22.1.0(@vue/compiler-sfc@3.5.13): + dependencies: + '@antfu/install-pkg': 1.0.0 + '@iconify/utils': 2.3.0 + debug: 4.4.0 + local-pkg: 1.1.1 + unplugin: 2.3.2 + optionalDependencies: + '@vue/compiler-sfc': 3.5.13 + transitivePeerDependencies: + - supports-color + + unplugin-utils@0.2.4: + dependencies: + pathe: 2.0.3 + picomatch: 4.0.2 + optional: true + + unplugin@2.3.2: + dependencies: + acorn: 8.14.1 + picomatch: 4.0.2 + webpack-virtual-modules: 0.6.2 + + untyped@2.0.0: + dependencies: + citty: 0.1.6 + defu: 6.1.4 + jiti: 2.4.2 + knitwork: 1.2.0 + scule: 1.3.0 + optional: true + + update-browserslist-db@1.1.3(browserslist@4.24.4): + dependencies: + browserslist: 4.24.4 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + vite-code-inspector-plugin@0.20.10: + dependencies: + code-inspector-core: 0.20.10 + transitivePeerDependencies: + - supports-color + + vite-plugin-cdn-import@1.0.1(rollup@4.40.0)(vite@6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1)): + dependencies: + rollup-plugin-external-globals: 0.10.0(rollup@4.40.0) + vite-plugin-externals: 0.6.2(vite@6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1)) + transitivePeerDependencies: + - rollup + - vite + + vite-plugin-compression@0.5.1(vite@6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1)): + dependencies: + chalk: 4.1.2 + debug: 4.4.0 + fs-extra: 10.1.0 + vite: 6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1) + transitivePeerDependencies: + - supports-color + + vite-plugin-externals@0.6.2(vite@6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1)): + dependencies: + acorn: 8.14.1 + es-module-lexer: 0.4.1 + fs-extra: 10.1.0 + magic-string: 0.25.9 + vite: 6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1) + + vite-plugin-fake-server@2.2.0: + dependencies: + bundle-import: 0.0.2 + chokidar: 4.0.3 + path-to-regexp: 8.2.0 + picocolors: 1.1.1 + tinyglobby: 0.2.13 + + vite-plugin-remove-console@2.2.0: {} + + vite-plugin-router-warn@1.0.0: {} + + vite-svg-loader@5.1.0(vue@3.5.13(typescript@5.8.3)): + dependencies: + svgo: 3.3.2 + vue: 3.5.13(typescript@5.8.3) + + vite@6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1): + dependencies: + esbuild: 0.25.3 + fdir: 6.4.4(picomatch@4.0.2) + picomatch: 4.0.2 + postcss: 8.5.3 + rollup: 4.40.0 + tinyglobby: 0.2.13 + optionalDependencies: + '@types/node': 20.17.30 + fsevents: 2.3.3 + jiti: 2.4.2 + lightningcss: 1.29.2 + sass: 1.87.0 + yaml: 2.7.1 + + vscode-uri@3.1.0: {} + + vue-demi@0.14.10(vue@3.5.13(typescript@5.8.3)): + dependencies: + vue: 3.5.13(typescript@5.8.3) + + vue-eslint-parser@10.1.3(eslint@9.25.1(jiti@2.4.2)): + dependencies: + debug: 4.4.0 + eslint: 9.25.1(jiti@2.4.2) + eslint-scope: 8.3.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 + esquery: 1.6.0 + lodash: 4.17.21 + semver: 7.7.1 + transitivePeerDependencies: + - supports-color + + vue-router@4.5.0(vue@3.5.13(typescript@5.8.3)): + dependencies: + '@vue/devtools-api': 6.6.4 + vue: 3.5.13(typescript@5.8.3) + + vue-tippy@6.7.0(vue@3.5.13(typescript@5.8.3)): + dependencies: + tippy.js: 6.3.7 + vue: 3.5.13(typescript@5.8.3) + + vue-tsc@2.2.10(typescript@5.8.3): + dependencies: + '@volar/typescript': 2.4.12 + '@vue/language-core': 2.2.10(typescript@5.8.3) + typescript: 5.8.3 + + vue-types@6.0.0(vue@3.5.13(typescript@5.8.3)): + optionalDependencies: + vue: 3.5.13(typescript@5.8.3) + + vue@3.5.13(typescript@5.8.3): + dependencies: + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-sfc': 3.5.13 + '@vue/runtime-dom': 3.5.13 + '@vue/server-renderer': 3.5.13(vue@3.5.13(typescript@5.8.3)) + '@vue/shared': 3.5.13 + optionalDependencies: + typescript: 5.8.3 + + webpack-code-inspector-plugin@0.20.10: + dependencies: + code-inspector-core: 0.20.10 + transitivePeerDependencies: + - supports-color + + webpack-virtual-modules@0.6.2: {} + + which@1.3.1: + dependencies: + isexe: 2.0.0 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + widest-line@5.0.0: + dependencies: + string-width: 7.2.0 + + word-wrap@1.2.5: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + wrap-ansi@9.0.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 7.2.0 + strip-ansi: 7.1.0 + + write-file-atomic@5.0.1: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + + xml-name-validator@4.0.0: {} + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yaml@2.7.1: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yocto-queue@0.1.0: {} + + yocto-queue@1.2.1: {} + + zrender@5.6.1: + dependencies: + tslib: 2.3.0 diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..cdc3694 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,8 @@ +// @ts-check + +/** @type {import('postcss-load-config').Config} */ +export default { + plugins: { + ...(process.env.NODE_ENV === "production" ? { cssnano: {} } : {}) + } +}; diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..bef93d4 --- /dev/null +++ b/public/favicon.ico Binary files differ diff --git a/public/logo.svg b/public/logo.svg new file mode 100644 index 0000000..a63d2b1 --- /dev/null +++ b/public/logo.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" class="icon" viewBox="0 0 1024 1024"><path fill="#386BF3" d="M410.558.109c0 210.974-300.876 361.752-300.876 633.548 0 174.943 134.704 316.787 300.876 316.787s300.877-141.817 300.877-316.787C711.408 361.752 410.558 210.974 410.558.109"/><path fill="#C3D2FB" d="M613.469 73.665c0 211.055-300.877 361.914-300.877 633.547C312.592 882.156 447.296 1024 613.47 1024s300.876-141.817 300.876-316.788C914.29 435.58 613.469 284.72 613.469 73.665"/><path fill="#303F5B" d="M312.592 707.212c0-183.713 137.636-312.171 226.723-441.39 81.702 106.112 172.12 218.74 172.12 367.726A309.755 309.755 0 0 1 420.36 950.064a323.1 323.1 0 0 1-107.769-242.852z"/></svg> \ No newline at end of file diff --git a/public/platform-config.json b/public/platform-config.json new file mode 100644 index 0000000..ff03f87 --- /dev/null +++ b/public/platform-config.json @@ -0,0 +1,26 @@ +{ + "Version": "6.0.0", + "Title": "PureAdmin", + "FixedHeader": true, + "HiddenSideBar": false, + "MultiTagsCache": false, + "KeepAlive": true, + "Layout": "vertical", + "Theme": "light", + "DarkMode": false, + "OverallStyle": "light", + "Grey": false, + "Weak": false, + "HideTabs": false, + "HideFooter": false, + "Stretch": false, + "SidebarStatus": true, + "EpThemeColor": "#409EFF", + "ShowLogo": true, + "ShowModel": "smart", + "MenuArrowIconNoTransition": false, + "CachingAsyncRoutes": false, + "TooltipEffect": "light", + "ResponsiveStorageNameSpace": "responsive-", + "MenuSearchHistory": 6 +} diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..7294c44 --- /dev/null +++ b/src/App.vue @@ -0,0 +1,26 @@ +<template> + <el-config-provider :locale="currentLocale"> + <router-view /> + <ReDialog /> + </el-config-provider> +</template> + +<script lang="ts"> +import { defineComponent } from "vue"; +import { ElConfigProvider } from "element-plus"; +import { ReDialog } from "@/components/ReDialog"; +import zhCn from "element-plus/es/locale/lang/zh-cn"; + +export default defineComponent({ + name: "app", + components: { + [ElConfigProvider.name]: ElConfigProvider, + ReDialog + }, + computed: { + currentLocale() { + return zhCn; + } + } +}); +</script> diff --git a/src/api/routes.ts b/src/api/routes.ts new file mode 100644 index 0000000..501ea3c --- /dev/null +++ b/src/api/routes.ts @@ -0,0 +1,10 @@ +import { http } from "@/utils/http"; + +type Result = { + success: boolean; + data: Array<any>; +}; + +export const getAsyncRoutes = () => { + return http.request<Result>("get", "/get-async-routes"); +}; diff --git a/src/api/user.ts b/src/api/user.ts new file mode 100644 index 0000000..87184b5 --- /dev/null +++ b/src/api/user.ts @@ -0,0 +1,45 @@ +import { http } from "@/utils/http"; + +export type UserResult = { + success: boolean; + data: { + /** 澶村儚 */ + avatar: string; + /** 鐢ㄦ埛鍚� */ + username: string; + /** 鏄电О */ + nickname: string; + /** 褰撳墠鐧诲綍鐢ㄦ埛鐨勮鑹� */ + roles: Array<string>; + /** 鎸夐挳绾у埆鏉冮檺 */ + permissions: Array<string>; + /** `token` */ + accessToken: string; + /** 鐢ㄤ簬璋冪敤鍒锋柊`accessToken`鐨勬帴鍙f椂鎵�闇�鐨刞token` */ + refreshToken: string; + /** `accessToken`鐨勮繃鏈熸椂闂达紙鏍煎紡'xxxx/xx/xx xx:xx:xx'锛� */ + expires: Date; + }; +}; + +export type RefreshTokenResult = { + success: boolean; + data: { + /** `token` */ + accessToken: string; + /** 鐢ㄤ簬璋冪敤鍒锋柊`accessToken`鐨勬帴鍙f椂鎵�闇�鐨刞token` */ + refreshToken: string; + /** `accessToken`鐨勮繃鏈熸椂闂达紙鏍煎紡'xxxx/xx/xx xx:xx:xx'锛� */ + expires: Date; + }; +}; + +/** 鐧诲綍 */ +export const getLogin = (data?: object) => { + return http.request<UserResult>("post", "/login", { data }); +}; + +/** 鍒锋柊`token` */ +export const refreshTokenApi = (data?: object) => { + return http.request<RefreshTokenResult>("post", "/refresh-token", { data }); +}; diff --git a/src/assets/home/BellFilled.png b/src/assets/home/BellFilled.png new file mode 100644 index 0000000..9af65c9 --- /dev/null +++ b/src/assets/home/BellFilled.png Binary files differ diff --git a/src/assets/home/Header.png b/src/assets/home/Header.png new file mode 100644 index 0000000..9046b80 --- /dev/null +++ b/src/assets/home/Header.png Binary files differ diff --git a/src/assets/home/banner.png b/src/assets/home/banner.png new file mode 100644 index 0000000..14f7a27 --- /dev/null +++ b/src/assets/home/banner.png Binary files differ diff --git a/src/assets/home/car.png b/src/assets/home/car.png new file mode 100644 index 0000000..74e9c5f --- /dev/null +++ b/src/assets/home/car.png Binary files differ diff --git a/src/assets/home/car1.png b/src/assets/home/car1.png new file mode 100644 index 0000000..81f16c8 --- /dev/null +++ b/src/assets/home/car1.png Binary files differ diff --git a/src/assets/home/daixie.png b/src/assets/home/daixie.png new file mode 100644 index 0000000..007393f --- /dev/null +++ b/src/assets/home/daixie.png Binary files differ diff --git a/src/assets/home/logo.png b/src/assets/home/logo.png new file mode 100644 index 0000000..ab1a6c8 --- /dev/null +++ b/src/assets/home/logo.png Binary files differ diff --git a/src/assets/home/notice.png b/src/assets/home/notice.png new file mode 100644 index 0000000..1acfb4b --- /dev/null +++ b/src/assets/home/notice.png Binary files differ diff --git a/src/assets/home/notice1.png b/src/assets/home/notice1.png new file mode 100644 index 0000000..82d6f40 --- /dev/null +++ b/src/assets/home/notice1.png Binary files differ diff --git a/src/assets/home/share.png b/src/assets/home/share.png new file mode 100644 index 0000000..f073a7e --- /dev/null +++ b/src/assets/home/share.png Binary files differ diff --git a/src/assets/home/vue.svg b/src/assets/home/vue.svg new file mode 100644 index 0000000..770e9d3 --- /dev/null +++ b/src/assets/home/vue.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg> \ No newline at end of file diff --git a/src/assets/home/xian.png b/src/assets/home/xian.png new file mode 100644 index 0000000..8ca94b6 --- /dev/null +++ b/src/assets/home/xian.png Binary files differ diff --git a/src/assets/iconfont/iconfont.css b/src/assets/iconfont/iconfont.css new file mode 100644 index 0000000..9a153df --- /dev/null +++ b/src/assets/iconfont/iconfont.css @@ -0,0 +1,27 @@ +@font-face { + font-family: "iconfont"; /* Project id 2208059 */ + src: + url("iconfont.woff2?t=1671895108120") format("woff2"), + url("iconfont.woff?t=1671895108120") format("woff"), + url("iconfont.ttf?t=1671895108120") format("truetype"); +} + +.iconfont { + font-family: "iconfont" !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.pure-iconfont-tabs:before { + content: "\e63e"; +} + +.pure-iconfont-logo:before { + content: "\e620"; +} + +.pure-iconfont-new:before { + content: "\e615"; +} diff --git a/src/assets/iconfont/iconfont.js b/src/assets/iconfont/iconfont.js new file mode 100644 index 0000000..fb89aea --- /dev/null +++ b/src/assets/iconfont/iconfont.js @@ -0,0 +1,68 @@ +(window._iconfont_svg_string_2208059 = + '<svg><symbol id="pure-iconfont-tabs" viewBox="0 0 1024 1024"><path d="M400.43383789 497.82763673c4.20227051 3.95507813 6.50939942 9.64050293 6.26220703 15.40832519 0.32958983 5.85021973-2.05993653 11.53564453-6.26220703 15.40832519-4.36706543 3.87268067-10.1348877 5.93261719-15.90270996 5.6854248h-57.3486328v193.71643067c0.16479492 6.09741211-2.38952637 11.86523438-6.92138672 15.73791504-4.53186037 4.44946289-10.62927247 6.83898926-16.8914795 6.67419433-6.26220703 0.24719239-12.4420166-2.22473145-16.89147949-6.67419436-4.36706543-4.03747559-6.7565918-9.80529786-6.67419434-15.73791501v-193.6340332H222.78491211c-5.93261719 0.24719239-11.70043946-1.89514161-15.90270997-6.01501466-4.28466797-3.95507813-6.59179689-9.64050293-6.26220701-15.40832519-0.24719239-5.76782227 2.05993653-11.28845215 6.26220702-15.07873536 4.36706543-3.95507813 10.05249023-6.01501465 15.90270996-5.76782224h163.4765625c5.19104004 0 10.21728516 2.05993653 14.17236328 5.6854248z m177.73132325 57.76062011c4.28466797 4.20227051 6.59179689 10.05249023 6.34460448 16.14990234v156.47277832c0.24719239 5.93261719-2.05993653 11.70043946-6.34460449 15.73791504-3.95507813 4.36706543-9.64050293 6.83898926-15.57312011 6.67419433-5.85021973 0.08239747-11.45324708-2.22473145-15.57312013-6.34460449-3.95507813-4.28466797-6.26220703-9.8876953-6.26220703-15.73791504-14.83154297 16.06750489-35.34851075 25.37841797-57.01904297 25.87280274-16.23229981 0.24719239-32.05261231-4.36706543-45.7305908-13.1011963-14.17236327-8.81652833-25.70800781-21.50573731-33.20617677-36.58447265-15.90270997-33.28857422-15.90270997-72.18017578 0-105.46875 7.33337403-15.16113281 18.86901856-27.85034179 33.20617677-36.58447266 13.18359375-8.6517334 28.67431641-13.26599122 44.41223145-13.10119628 21.67053223-0.08239747 42.68188475 8.07495117 58.66699218 22.82409667-0.16479492-6.01501465 2.14233398-11.86523438 6.34460448-16.14990234 8.73413086-8.40454102 22.41210938-8.40454102 31.14624024 0l-0.41198731-0.65917969z m-50.42724611 139.0045166c19.85778809-26.03759766 19.85778809-62.29248047 0-88.33007813-9.47570801-11.78283692-23.81286622-18.37463379-38.80920409-17.79785156-14.7491455-0.41198731-28.92150879 6.09741211-38.15002442 17.79785156-9.97009278 12.35961914-15.24353028 28.01513673-14.91394043 44.00024414-0.49438477 16.06750489 4.69665529 31.80541991 14.58435058 44.32983399 9.55810548 11.45324708 23.73046875 17.88024903 38.47961427 17.46826172 14.91394043 0.32958983 29.08630372-6.09741211 38.8092041-17.46826172zM778.47338867 562.26245117c14.08996583 8.81652833 25.54321289 21.34094239 33.20617676 36.25488281 8.15734864 16.31469727 12.27722169 34.44213867 11.94763184 52.734375 0.32958983 18.37463379-3.7902832 36.58447265-11.94763184 53.06396485-7.41577148 15.07873536-18.95141602 27.76794434-33.20617676 36.58447266-13.18359375 8.73413086-28.67431641 13.26599122-44.41223144 13.10119629-11.45324708 0.16479492-22.82409669-2.38952637-33.20617676-7.41577149-9.55810548-4.11987305-18.20983887-10.05249023-25.54321289-17.46826171v2.30712889c0.16479492 5.93261719-2.05993653 11.70043946-6.17980957 15.98510744-4.11987305 4.20227051-9.80529786 6.59179689-15.73791506 6.5093994-5.85021973 0.24719239-11.53564453-2.05993653-15.5731201-6.34460449-4.28466797-4.20227051-6.59179689-10.05249023-6.26220704-16.14990233V499.80517578c-0.16479492-6.01501465 2.05993653-11.86523438 6.26220705-16.14990234 8.73413086-8.48693847 22.41210938-8.48693847 31.14624023 0 4.20227051 4.28466797 6.50939942 10.05249023 6.26220703 16.14990234v76.87683106c6.59179689-8.07495117 14.83154297-14.58435059 24.22485352-19.11621094 10.21728516-5.60302734 21.58813477-8.48693847 33.20617675-8.40454102 16.23229981-0.16479492 32.13500977 4.36706543 45.81298828 13.10119629z m-12.93640137 134.30786133c10.05249023-12.4420166 15.32592773-28.26232911 14.91394043-44.32983398 0.49438477-15.98510742-4.69665529-31.55822755-14.58435059-44.00024415-9.8876953-11.04125977-23.89526367-17.38586426-38.64440917-17.38586426s-28.75671387 6.3446045-38.64440918 17.38586426c-19.85778809 26.03759766-19.85778809 62.29248047 0 88.33007813 9.55810548 11.61804201 23.89526367 18.20983887 38.8092041 17.79785156 15.07873536-0.16479492 29.16870117-7.49816895 38.15002442-19.77539062v1.97753906zM673.5814209 299.00256347c-12.77160645 0-23.07128906-10.29968262-23.07128907-23.07128905V183.5637207c-0.08239747-6.59179689 0-13.10119629 0-19.6105957V154.31262207c0-12.77160645 10.29968262-23.07128906 23.07128906-23.07128906H820.16650391c14.00756836 0 27.10876465 5.43823242 37.07885742 15.32592773 9.31091309 9.31091309 14.66674805 21.42333983 15.32592773 34.44213868 0.08239747 0.57678223 0.08239747 1.15356445 0.08239746 1.73034667v93.27392579c0 12.77160645-10.29968262 23.07128906-23.07128906 23.07128906H673.5814209z m23.07128906-46.1425781h129.69360352v-69.29626467c0-1.64794922-0.65917969-3.21350098-1.81274415-4.44946289-1.15356445-1.15356445-2.80151367-1.81274414-4.44946289-1.81274414H696.65270999v75.5584717zM396.56115722 299.90893555c-12.77160645 0-23.07128906-10.29968262-23.07128905-23.07128908V155.13659668c0-12.68920898 10.29968262-22.98889161 22.9888916-23.07128906l175.83618164-0.90637207h0.08239746c14.00756836 0 27.10876465 5.43823242 37.07885742 15.32592774 9.8876953 9.97009278 15.32592773 23.07128906 15.32592775 37.07885741v93.27392579c0 12.77160645-10.29968262 23.07128906-23.07128907 23.07128906h-205.16967775z m23.07128907-46.22497559h159.0270996v-70.20263671c0-1.64794922-0.65917969-3.21350098-1.81274413-4.44946289-1.15356445-1.15356445-2.71911623-1.81274414-4.36706543-1.81274414l-152.84729005 0.74157713v75.72326662z" ></path><path d="M149.78076171 892.84106445c-14.25476075 0-27.60314942-5.52062989-37.65563964-15.40832519-10.05249023-9.97009278-15.57312012-23.15368653-15.57312012-37.16125488V183.72851562c0-29.00390624 23.89526367-52.56958007 53.22875978-52.56958007h139.25170897c14.25476075 0 27.60314942 5.43823242 37.65563966 15.40832519 10.05249023 9.8876953 15.57312012 23.15368653 15.57312011 37.16125489V323.30981445c0 1.64794922 0.65917969 3.21350098 1.89514162 4.44946289 1.23596192 1.15356445 2.80151367 1.81274414 4.44946288 1.81274414h525.61340332c14.25476075 0 27.60314942 5.43823242 37.65563964 15.4083252 10.05249023 9.8876953 15.57312012 23.07128906 15.57312012 37.16125488v458.12988281c0 14.08996583-5.52062989 27.27355958-15.57312012 37.16125489s-23.40087891 15.40832519-37.65563964 15.40832519H149.78076171z m6.34460451-709.11254882c-3.54309083 0-6.3446045 2.80151367-6.34460449 6.26220703v649.86877441c0 1.64794922 0.65917969 3.29589844 1.8951416 4.4494629 1.15356445 1.15356445 2.80151367 1.81274414 4.44946288 1.81274415h718.09387208c1.73034668 0 3.29589844-0.65917969 4.44946288-1.81274415 1.23596192-1.15356445 1.89514161-2.71911623 1.89514161-4.4494629V379.01049805c0-1.64794922-0.65917969-3.21350098-1.81274413-4.36706544-1.23596192-1.23596192-2.80151367-1.89514161-4.44946291-1.89514159h-525.69580077c-14.25476075 0-27.60314942-5.52062989-37.65563966-15.4083252-10.05249023-9.8876953-15.57312012-23.15368653-15.57312012-37.16125488V189.90832519c0-1.64794922-0.65917969-3.21350098-1.8951416-4.44946288-1.15356445-1.15356445-2.80151367-1.81274414-4.44946289-1.81274416H156.12536621z" ></path></symbol><symbol id="pure-iconfont-logo" viewBox="0 0 1024 1024"><path d="M410.558481 0.10861C410.558481 211.083075 109.682285 361.860579 109.682285 633.656511c0 174.943176 134.703259 316.787527 300.876196 316.787527s300.876197-141.817198 300.876197-316.787527C711.407525 361.751969 410.558481 210.974465 410.558481 0.10861z" fill="#386BF3" ></path><path d="M613.468671 73.664572c0 211.055922-300.876197 361.914883-300.876196 633.547901 0 174.943176 134.703259 316.787527 300.876196 316.787527s300.876197-141.817198 300.876197-316.787527c-0.054305-271.633018-300.876197-422.491979-300.876197-633.547901z" fill="#C3D2FB" ></path><path d="M312.592475 707.212473c0-183.713414 137.635722-312.171612 226.72288-441.390078 81.701694 106.111739 172.119322 218.740063 172.119323 367.725506a309.755045 309.755045 0 0 1-291.074166 316.516003 323.114046 323.114046 0 0 1-107.768037-242.851431z" fill="#303F5B" ></path></symbol><symbol id="pure-iconfont-new" viewBox="0 0 1024 1024"><path d="M466.73632812 228.81640625l-33.31054687 255.41015625c34.36523438 20.21484375 78.31054688 42.62695313 131.22070313 62.2265625 55.1953125 20.47851563 105.1171875 32.43164063 145.54687499 39.46289063 127.44140625-161.27929688 147.39257813-224.38476563 141.59179688-215.59570313-10.45898438 15.99609375-62.05078125 20.390625-76.20117188 15.29296875-28.30078125-10.10742188-53.4375-37.52929688-65.30273437-81.29882813-14.85351563-54.66796875-43.50585938-50.53710938-94.5703125-21.35742187-58.88671875 33.48632813-121.46484375 4.39453125-148.97460938-54.140625z" fill="#FFFFFF" ></path><path d="M444.76367187 228.81640625c-3.77929688 28.828125-7.55859375 57.74414063-11.33789062 86.57226563l-17.9296875 137.37304687c-1.40625 10.45898438-2.72460938 21.00585938-4.13085937 31.46484375-0.96679688 7.3828125 4.83398438 15.46875 10.8984375 18.984375 69.78515625 40.86914063 145.63476563 71.98242188 224.12109374 91.66992188 19.16015625 4.83398438 38.49609375 8.87695313 57.91992188 12.30468749 7.20703125 1.23046875 16.34765625 0.703125 21.35742188-5.625C767.49804688 548.65039063 808.3671875 494.421875 843.34765625 436.58984375c7.91015625-13.09570313 15.55664063-26.3671875 22.1484375-40.16601563 2.4609375-5.09765625 4.74609375-10.37109375 6.85546875-15.64453125 1.31835938-3.33984375 2.37304688-7.11914063 2.28515625-10.72265625-0.43945313-12.04101563-9.4921875-22.32421875-22.06054688-22.32421875-8.4375 0-14.94140625 4.5703125-19.42382812 11.33789063-1.93359375 2.8125 3.33984375-3.42773438 1.58203125-2.109375-0.43945313 0.3515625-0.87890625 0.79101563-1.23046875 1.14257812-1.31835938 1.49414063-3.33984375 1.14257813 2.54882813-1.84570312-1.23046875 0.61523438-2.37304688 1.58203125-3.60351563 2.28515625-1.14257813 0.61523438-2.28515625 1.14257813-3.33984375 1.66992187-3.33984375 1.66992188 5.53710938-2.109375 1.93359375-0.87890625-0.61523438 0.17578125-1.14257813 0.43945313-1.7578125 0.61523438-3.07617188 1.0546875-6.24023438 1.93359375-9.40429688 2.72460937-3.33984375 0.79101563-6.76757813 1.40625-10.10742187 2.02148438-5.625 0.87890625 5.36132813-0.61523438-0.3515625 0.08789062-1.66992188 0.17578125-3.42773438 0.3515625-5.09765625 0.52734375-6.15234375 0.52734375-12.3046875 0.703125-18.45703125 0.26367188-2.28515625-0.17578125-7.03125-1.40625 1.40625 0.3515625-1.0546875-0.17578125-2.109375-0.3515625-3.1640625-0.61523438-0.703125-0.17578125-1.40625-0.3515625-2.109375-0.61523437-0.79101563-0.26367188-1.58203125-0.61523438-2.37304688-0.87890625-3.42773438-1.23046875 5.09765625 2.37304688 1.49414063 0.61523437-2.98828125-1.40625-5.88867188-2.8125-8.70117188-4.48242187-1.31835938-0.79101563-2.72460938-1.66992188-3.95507812-2.54882813l-2.63671875-1.84570312c-1.40625-1.0546875-3.69140625-3.69140625 1.0546875 0.79101562-2.37304688-2.28515625-5.09765625-4.30664063-7.47070313-6.59179687-2.98828125-2.98828125-5.44921875-6.59179688-8.52539062-9.4921875 0.17578125 0.17578125 3.33984375 4.48242188 1.23046875 1.58203125-0.61523438-0.79101563-1.23046875-1.66992188-1.7578125-2.4609375-1.0546875-1.49414063-2.109375-3.07617188-3.07617188-4.65820313-2.4609375-3.77929688-4.65820313-7.734375-6.67968749-11.77734375-0.87890625-1.7578125-1.7578125-3.60351563-2.63671875-5.44921875-0.17578125-0.43945313-0.3515625-0.79101563-0.52734375-1.23046875-0.96679688-2.19726563-0.703125-1.66992188 0.61523437 1.40625 0.08789063-0.3515625-0.96679688-2.54882813-1.0546875-2.63671875-1.7578125-4.48242188-3.25195313-9.140625-4.65820313-13.7109375-2.72460938-9.22851563-5.625-18.19335938-9.66796874-26.89453125-6.85546875-14.50195313-18.19335938-26.10351563-33.31054688-31.640625-13.18359375-4.83398438-28.38867188-3.07617188-41.484375 1.0546875-16.171875 5.09765625-30.84960938 13.44726563-45.61523438 21.4453125-2.02148438 1.0546875-3.95507813 2.109375-6.06445312 3.07617188-0.52734375 0.26367188-4.65820313 1.84570313-0.96679688 0.52734375 3.60351563-1.40625-0.43945313 0.17578125-0.96679687 0.3515625-3.95507813 1.49414063-7.99804688 2.8125-12.04101563 3.8671875-2.02148438 0.52734375-3.95507813 0.96679688-5.9765625 1.31835937-0.79101563 0.17578125-1.58203125 0.26367188-2.37304687 0.43945313-4.48242188 0.79101563 5.625-0.52734375 1.0546875-0.17578125-3.95507813 0.3515625-7.91015625 0.61523438-11.86523438 0.52734375-1.93359375 0-3.8671875-0.08789063-5.88867187-0.26367188-0.79101563-0.08789063-1.58203125-0.17578125-2.28515625-0.17578125-4.30664063-0.3515625 4.74609375 0.79101563 1.84570312 0.26367188-3.95507813-0.79101563-7.99804688-1.40625-11.86523437-2.54882813-3.515625-0.96679688-6.94335938-2.37304688-10.37109375-3.60351562-2.72460938-0.96679688 5.2734375 2.4609375 1.49414062 0.61523437-0.703125-0.3515625-1.40625-0.61523438-2.109375-0.96679687-2.109375-1.0546875-4.13085938-2.109375-6.24023437-3.25195313-3.07617188-1.7578125-6.06445313-3.69140625-8.96484375-5.71289062-0.96679688-0.703125-1.84570313-1.49414063-2.90039063-2.109375 0.26367188 0.17578125 4.30664063 3.515625 1.58203125 1.23046875-1.66992188-1.40625-3.42773438-2.8125-5.00976562-4.30664063-2.90039063-2.63671875-5.625-5.36132813-8.17382813-8.17382812-1.40625-1.49414063-2.72460938-3.07617188-4.04296875-4.65820313-0.52734375-0.61523438-0.96679688-1.40625-1.58203125-1.93359375 4.39453125 4.39453125 1.14257813 1.40625 0-0.08789062-4.921875-6.85546875-9.140625-14.0625-12.65625-21.70898438-4.921875-10.37109375-20.65429688-13.97460938-30.05859375-7.91015625-10.72265625 6.94335938-13.18359375 18.89648438-7.91015625 30.05859375 15.8203125 33.31054688 43.68164063 60.20507813 78.48632813 72.68554688 15.55664063 5.625 33.13476563 7.734375 49.5703125 5.80078125 9.58007813-1.14257813 18.984375-2.8125 28.125-6.15234375 9.66796875-3.515625 18.54492188-8.0859375 27.421875-13.0078125 6.85546875-3.77929688 14.23828125-8.52539063 21.70898437-10.8984375-0.08789063 0-5.44921875 2.19726563-2.28515625 0.96679688 0.79101563-0.3515625 1.58203125-0.61523438 2.4609375-0.96679688 1.40625-0.52734375 2.8125-1.0546875 4.30664063-1.58203125 2.90039063-0.96679688 5.88867188-1.84570313 8.96484375-2.54882813 1.40625-0.26367188 2.8125-0.43945313 4.21875-0.79101562-7.64648438 1.84570313-3.42773438 0.43945313-1.0546875 0.3515625 1.14257813-0.08789063 2.28515625-0.08789063 3.42773437 0 0.61523438 0 1.23046875 0.08789063 1.84570313 0.08789063 3.25195313 0.08789063-6.06445313-1.31835938-2.98828125-0.3515625 1.14257813 0.3515625 2.28515625 0.52734375 3.42773437 0.87890625 0.43945313 0.17578125 0.87890625 0.3515625 1.31835938 0.43945312 3.07617188 0.87890625-5.09765625-2.4609375-2.98828125-1.23046875 0.96679688 0.52734375 1.93359375 0.96679688 2.8125 1.49414063 0.52734375 0.3515625 0.96679688 0.703125 1.49414062 0.96679687 1.93359375 1.14257813-5.00976563-4.21875-2.109375-1.58203125 0.87890625 0.79101563 1.7578125 1.58203125 2.54882813 2.37304688 1.93359375 2.02148438 2.90039063 5.00976563-0.26367188-0.703125 1.49414063 2.63671875 3.42773438 5.00976563 4.83398438 7.73437499 0.79101563 1.49414063 1.40625 3.07617188 2.19726562 4.5703125-3.42773438-6.59179688-0.43945313-1.0546875 0.26367188 0.96679688 1.40625 3.95507813 2.63671875 8.0859375 3.77929687 12.12890625 5.09765625 18.10546875 12.83203125 36.12304688 23.90625 51.41601563 10.37109375 14.23828125 22.76367188 26.80664063 38.14453125 35.59570312 6.41601563 3.69140625 13.53515625 7.29492188 20.7421875 8.96484375 6.41601563 1.49414063 13.27148438 2.02148438 19.86328125 2.02148438 14.67773438 0.08789063 30.05859375-1.7578125 44.12109375-5.88867188 6.85546875-2.02148438 13.88671875-4.5703125 19.95117188-8.34960938 6.59179688-4.13085938 9.84375-8.4375 14.67773437-14.23828124-3.515625 4.21875-2.90039063 4.48242188-7.47070312 7.47070312-2.63671875 1.66992188-7.734375 3.1640625-10.98632813 2.98828125-1.84570313-0.52734375-3.69140625-0.96679688-5.53710937-1.49414063-5.88867188-0.61523438-10.37109375-3.69140625-13.359375-9.31640624-1.84570313-3.1640625-3.07617188-7.47070313-2.98828125-10.81054688 0-0.26367188 1.7578125-7.99804688 0.43945312-4.13085938-0.3515625 1.0546875-0.703125 2.109375-1.14257812 3.16406251-0.26367188 0.61523438-0.52734375 1.31835938-0.79101563 1.93359375-1.0546875 2.72460938 2.90039063-6.59179688 1.58203125-3.77929688-0.17578125 0.43945313-0.3515625 0.87890625-0.61523437 1.31835938-5.18554688 11.68945313-11.33789063 22.8515625-17.75390625 33.92578125-29.53125 51.15234375-64.59960938 99.140625-100.546875 145.81054687-0.703125 0.87890625-1.31835938 1.7578125-2.02148438 2.54882813-2.37304688 3.1640625 0 0 0.43945313-0.52734375-1.66992188 2.19726563-3.42773438 4.39453125-5.09765625 6.59179687-3.515625 4.5703125-7.11914063 9.05273438-10.63476563 13.53515625 7.11914063-1.84570313 14.23828125-3.77929688 21.35742188-5.625-36.82617188-6.50390625-73.125-15.46875-108.72070313-26.80664063-20.65429688-6.59179688-40.95703125-13.97460938-60.99609375-22.14843749-2.28515625-0.87890625-4.48242188-1.84570313-6.76757812-2.81250001-4.921875-2.02148438 3.1640625 1.40625 0.08789062 0l-3.69140625-1.58203125c-4.74609375-2.109375-9.58007813-4.21875-14.32617187-6.328125-8.61328125-3.8671875-17.13867188-7.99804688-25.6640625-12.12890624-17.49023438-8.61328125-34.62890625-17.9296875-51.41601563-27.77343751 3.60351563 6.328125 7.29492188 12.65625 10.8984375 18.98437501 3.77929688-28.828125 7.55859375-57.74414063 11.33789063-86.57226563l17.9296875-137.37304688c1.40625-10.45898438 2.72460938-21.00585938 4.13085937-31.46484374 0.703125-5.18554688-2.90039063-12.04101563-6.41601562-15.55664063-3.77929688-3.77929688-10.10742188-6.6796875-15.55664063-6.41601562-5.71289063 0.26367188-11.6015625 2.109375-15.55664062 6.41601562-4.04296875 4.65820313-5.44921875 9.4921875-6.24023438 15.64453125z" fill="#FFCB40" ></path><path d="M496.61914062 458.73828125c47.54882813 31.640625 101.07421875 54.75585938 156.70898438 67.58789063 11.16210938 2.54882813 24.34570313-3.42773438 27.0703125-15.38085938 2.54882813-11.25-3.33984375-24.2578125-15.38085938-27.0703125-13.18359375-3.07617188-26.27929688-6.6796875-39.19921874-10.8984375-6.41601563-2.109375-12.83203125-4.30664063-19.16015625-6.76757813-3.42773438-1.31835938-6.85546875-2.63671875-10.1953125-3.95507812-1.49414063-0.61523438-2.90039063-1.14257813-4.30664063-1.7578125-4.13085938-1.7578125 4.04296875 1.7578125-1.23046875-0.52734375-25.13671875-10.8984375-49.21875-24.08203125-72.0703125-39.28710938-9.58007813-6.41601563-24.69726563-2.19726563-30.05859375 7.91015625-5.88867188 11.07421875-2.37304688 23.29101563 7.82226563 30.14648438z" fill="#FFCB40" ></path><path d="M245.77929687 729.6171875v-72.50976563-115.04882812V515.515625c-13.62304688 3.69140625-27.33398438 7.3828125-40.95703124 11.07421875 11.42578125 24.16992188 22.8515625 48.42773438 34.18945312 72.59765625 18.01757813 38.23242188 36.12304688 76.55273438 54.140625 114.78515625 4.21875 8.87695313 8.34960938 17.75390625 12.56835938 26.54296875 3.95507813 8.34960938 16.171875 12.91992188 24.78515624 10.10742188 9.22851563-2.98828125 16.171875-11.25 16.17187501-21.18164063v-72.50976563V541.8828125v-26.54296875c0-11.51367188-10.10742188-22.5-21.97265626-21.97265625-11.86523438 0.52734375-21.97265625 9.66796875-21.97265624 21.97265625v214.1015625c13.62304688-3.69140625 27.33398438-7.3828125 40.95703124-11.07421875-11.42578125-24.16992188-22.8515625-48.42773438-34.18945312-72.59765625-18.01757813-38.23242188-36.12304688-76.55273438-54.140625-114.78515625-4.21875-8.87695313-8.34960938-17.75390625-12.56835938-26.54296875-3.95507813-8.34960938-16.171875-12.91992188-24.78515624-10.10742188-9.22851563 2.98828125-16.171875 11.25-16.17187501 21.18164063v214.1015625c0 11.51367188 10.10742188 22.5 21.97265626 21.97265625 11.953125-0.52734375 21.97265625-9.66796875 21.97265624-21.97265625zM501.8046875 493.63085937H400.90625c-11.86523438 0-21.97265625 10.10742188-21.97265625 21.97265626v211.55273437c0 11.86523438 10.10742188 21.97265625 21.97265625 21.97265625h100.8984375c11.51367188 0 22.5-10.10742188 21.97265625-21.97265625-0.52734375-11.86523438-9.66796875-21.97265625-21.97265625-21.97265625H400.90625l21.97265625 21.97265625v-71.27929688-114.16992187-26.10351563l-21.97265625 21.97265626h100.8984375c11.51367188 0 22.5-10.10742188 21.97265625-21.97265626-0.52734375-11.86523438-9.66796875-21.97265625-21.97265625-21.97265624z" fill="#4381FF" ></path><path d="M478.16210937 595.75976563c-25.75195313 0.17578125-51.50390625 0.43945313-77.25585937-1e-8-11.51367188-0.17578125-22.5 10.1953125-21.97265625 21.97265625 0.52734375 12.04101563 9.66796875 21.796875 21.97265625 21.97265625 25.75195313 0.43945313 51.50390625 0.17578125 77.25585938 0 11.51367188-0.08789063 22.5-10.01953125 21.97265624-21.97265625-0.52734375-11.86523438-9.58007813-22.06054688-21.97265625-21.97265625zM553.57226563 515.60351563v214.10156249c0 9.31640625 6.76757813 19.07226563 16.171875 21.18164063 9.58007813 2.19726563 19.59960938-1.49414063 24.78515625-10.10742187 18.72070313-31.20117188 37.44140625-62.40234375 56.25-93.69140626 2.63671875-4.48242188 5.36132813-8.87695313 7.99804687-13.359375h-37.96875c18.72070313 31.20117188 37.44140625 62.40234375 56.25 93.69140625 2.63671875 4.48242188 5.36132813 8.87695313 7.99804688 13.359375 4.83398438 7.99804688 15.55664063 13.09570313 24.78515624 10.10742188 9.22851563-2.98828125 16.171875-11.25 16.17187501-21.18164063v-72.50976562-115.04882813-26.54296875c0-11.51367188-10.10742188-22.5-21.97265626-21.97265625-11.86523438 0.52734375-21.97265625 9.66796875-21.97265624 21.97265625v214.10156251c13.62304688-3.69140625 27.33398438-7.3828125 40.95703124-11.07421876-18.72070313-31.20117188-37.44140625-62.40234375-56.25-93.69140624-2.63671875-4.48242188-5.36132813-8.87695313-7.99804687-13.359375-8.52539063-14.23828125-29.44335938-14.23828125-37.96875 0-18.72070313 31.20117188-37.44140625 62.40234375-56.25 93.69140625-2.63671875 4.48242188-5.36132813 8.87695313-7.99804688 13.359375 13.62304688 3.69140625 27.33398438 7.3828125 40.95703126 11.07421875v-72.50976563-115.04882812-26.54296875c0-11.51367188-10.10742188-22.5-21.97265625-21.97265625-11.86523438 0.52734375-21.97265625 9.66796875-21.97265625 21.97265625z" fill="#4381FF" ></path><path d="M225.30078125 709.49023438v-72.50976563-115.04882813-26.54296874c-13.62304688 3.69140625-27.33398438 7.3828125-40.95703125 11.07421875 11.42578125 24.08203125 22.76367188 48.1640625 34.18945313 72.33398437 18.19335938 38.40820313 36.38671875 76.81640625 54.4921875 115.22460938 4.13085938 8.7890625 8.34960938 17.66601563 12.48046875 26.45507812 3.95507813 8.34960938 16.171875 12.91992188 24.78515625 10.10742187 9.22851563-2.98828125 16.171875-11.25 16.171875-21.18164062v-72.50976563-115.04882812V495.30078125c0-11.51367188-10.10742188-22.5-21.97265625-21.97265625-11.86523438 0.52734375-21.97265625 9.66796875-21.97265625 21.97265625v214.1015625c13.62304688-3.69140625 27.33398438-7.3828125 40.95703125-11.07421875-11.42578125-24.08203125-22.76367188-48.1640625-34.18945313-72.33398438-18.19335938-38.40820313-36.38671875-76.81640625-54.4921875-115.22460937-4.13085938-8.7890625-8.34960938-17.66601563-12.48046875-26.45507813-3.95507813-8.34960938-16.171875-12.91992188-24.78515625-10.10742187-9.22851563 2.98828125-16.171875 11.25-16.171875 21.18164063v214.10156249c0 11.51367188 10.10742188 22.5 21.97265625 21.97265626 11.86523438-0.52734375 21.97265625-9.66796875 21.97265625-21.97265625zM482.29296875 473.50390625H381.04296875c-11.86523438 0-21.97265625 10.10742188-21.97265625 21.97265625v211.55273438c0 11.86523438 10.10742188 21.97265625 21.97265625 21.97265624h101.25c11.51367188 0 22.5-10.10742188 21.97265625-21.97265625-0.52734375-11.86523438-9.66796875-21.97265625-21.97265625-21.97265625H381.04296875l21.97265625 21.97265625v-71.27929687-114.16992188-26.10351562l-21.97265625 21.97265625h101.25c11.51367188 0 22.5-10.10742188 21.97265625-21.97265625-0.52734375-11.86523438-9.66796875-21.97265625-21.97265625-21.97265625z" fill="#FF642E" ></path><path d="M458.5625 575.6328125c-25.83984375 0.17578125-51.76757813 0.43945313-77.60742188 0-11.51367188-0.17578125-22.5 10.1953125-21.97265624 21.97265625 0.52734375 12.04101563 9.66796875 21.796875 21.97265625 21.97265625 25.83984375 0.43945313 51.76757813 0.17578125 77.60742187 0 11.51367188-0.08789063 22.5-10.01953125 21.97265625-21.97265625-0.52734375-11.86523438-9.58007813-21.97265625-21.97265625-21.97265625zM534.32421875 495.4765625v214.1015625c0 9.31640625 6.76757813 19.07226563 16.171875 21.18164063 9.58007813 2.19726563 19.59960938-1.49414063 24.78515625-10.10742188 18.80859375-31.2890625 37.6171875-62.49023438 56.51367188-93.77929688 2.63671875-4.39453125 5.2734375-8.7890625 7.99804687-13.18359374h-37.96875c18.80859375 31.2890625 37.6171875 62.49023438 56.51367188 93.77929687 2.63671875 4.39453125 5.2734375 8.7890625 7.99804687 13.18359375 4.83398438 7.99804688 15.55664063 13.09570313 24.78515625 10.10742188 9.22851563-2.98828125 16.171875-11.25 16.171875-21.18164063v-72.50976563-115.04882812-26.54296875c0-11.51367188-10.10742188-22.5-21.97265625-21.97265625-11.86523438 0.52734375-21.97265625 9.66796875-21.97265625 21.97265625v214.1015625c13.62304688-3.69140625 27.33398438-7.3828125 40.95703125-11.07421875-18.80859375-31.2890625-37.6171875-62.49023438-56.51367188-93.77929688-2.63671875-4.39453125-5.2734375-8.7890625-7.99804687-13.18359374-8.52539063-14.23828125-29.35546875-14.23828125-37.96875 0-18.80859375 31.2890625-37.6171875 62.49023438-56.51367188 93.77929687-2.63671875 4.39453125-5.2734375 8.7890625-7.99804687 13.18359375 13.62304688 3.69140625 27.33398438 7.3828125 40.95703125 11.07421875v-72.50976563-115.04882812-26.54296875c0-11.51367188-10.10742188-22.5-21.97265625-21.97265625-11.86523438 0.52734375-21.97265625 9.66796875-21.97265625 21.97265625z" fill="#FF642E" ></path><path d="M629.0703125 793.77734375h74.8828125" fill="#FFFFFF" ></path><path d="M629.0703125 815.75h74.97070313c11.51367188 0 22.5-10.10742188 21.97265624-21.97265625-0.52734375-11.86523438-9.66796875-21.97265625-21.97265625-21.97265625h-74.97070312c-11.51367188 0-22.5 10.10742188-21.97265625 21.97265625 0.52734375 11.86523438 9.66796875 21.97265625 21.97265625 21.97265625z" fill="#FFCB40" ></path><path d="M552.16601563 793.77734375h5.71289062" fill="#FFFFFF" ></path><path d="M552.16601563 815.75h5.71289062c2.98828125 0.08789063 5.88867188-0.52734375 8.4375-1.93359375 2.72460938-0.87890625 5.09765625-2.37304688 7.03125-4.5703125 2.109375-2.02148438 3.69140625-4.30664063 4.5703125-7.03125 1.40625-2.63671875 2.02148438-5.44921875 1.93359375-8.4375l-0.79101562-5.80078125c-1.0546875-3.69140625-2.90039063-6.94335938-5.625-9.66796875-4.30664063-3.95507813-9.58007813-6.41601563-15.55664063-6.41601563h-5.71289062c-2.98828125-0.08789063-5.88867188 0.52734375-8.4375 1.93359376-2.72460938 0.87890625-5.09765625 2.37304688-7.03125 4.5703125-2.109375 2.02148438-3.69140625 4.30664063-4.5703125 7.03125-1.40625 2.63671875-2.02148438 5.44921875-1.93359375 8.43749999l0.79101562 5.80078126c1.0546875 3.69140625 2.90039063 6.94335938 5.625 9.66796874 4.30664063 3.95507813 9.58007813 6.41601563 15.55664063 6.41601563z" fill="#FFCB40" ></path></symbol></svg>'), + (function (e) { + var t = (t = document.getElementsByTagName("script"))[t.length - 1], + c = t.getAttribute("data-injectcss"), + t = t.getAttribute("data-disable-injectsvg"); + if (!t) { + var n, + l, + i, + o, + a, + h = function (t, c) { + c.parentNode.insertBefore(t, c); + }; + if (c && !e.__iconfont__svg__cssinject__) { + e.__iconfont__svg__cssinject__ = !0; + try { + document.write( + "<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>" + ); + } catch (t) { + console && console.log(t); + } + } + (n = function () { + var t, + c = document.createElement("div"); + (c.innerHTML = e._iconfont_svg_string_2208059), + (c = c.getElementsByTagName("svg")[0]) && + ((c.style.position = "absolute"), + (c.style.width = 0), + (c.style.height = 0), + (c.style.overflow = "hidden"), + (c = c), + (t = document.body).firstChild + ? h(c, t.firstChild) + : t.appendChild(c)); + }), + document.addEventListener + ? ~["complete", "loaded", "interactive"].indexOf(document.readyState) + ? setTimeout(n, 0) + : ((l = function () { + document.removeEventListener("DOMContentLoaded", l, !1), n(); + }), + document.addEventListener("DOMContentLoaded", l, !1)) + : document.attachEvent && + ((i = n), + (o = e.document), + (a = !1), + v(), + (o.onreadystatechange = function () { + "complete" == o.readyState && + ((o.onreadystatechange = null), d()); + })); + } + function d() { + a || ((a = !0), i()); + } + function v() { + try { + o.documentElement.doScroll("left"); + } catch (t) { + return void setTimeout(v, 50); + } + d(); + } + })(window); diff --git a/src/assets/iconfont/iconfont.json b/src/assets/iconfont/iconfont.json new file mode 100644 index 0000000..cec4806 --- /dev/null +++ b/src/assets/iconfont/iconfont.json @@ -0,0 +1,30 @@ +{ + "id": "2208059", + "name": "pure-admin", + "font_family": "iconfont", + "css_prefix_text": "pure-iconfont-", + "description": "pure-admin-iconfont", + "glyphs": [ + { + "icon_id": "20594647", + "name": "Tabs", + "font_class": "tabs", + "unicode": "e63e", + "unicode_decimal": 58942 + }, + { + "icon_id": "22129506", + "name": "PureLogo", + "font_class": "logo", + "unicode": "e620", + "unicode_decimal": 58912 + }, + { + "icon_id": "7795615", + "name": "New", + "font_class": "new", + "unicode": "e615", + "unicode_decimal": 58901 + } + ] +} diff --git a/src/assets/iconfont/iconfont.ttf b/src/assets/iconfont/iconfont.ttf new file mode 100644 index 0000000..82efcf8 --- /dev/null +++ b/src/assets/iconfont/iconfont.ttf Binary files differ diff --git a/src/assets/iconfont/iconfont.woff b/src/assets/iconfont/iconfont.woff new file mode 100644 index 0000000..0fdaa0a --- /dev/null +++ b/src/assets/iconfont/iconfont.woff Binary files differ diff --git a/src/assets/iconfont/iconfont.woff2 b/src/assets/iconfont/iconfont.woff2 new file mode 100644 index 0000000..e957d74 --- /dev/null +++ b/src/assets/iconfont/iconfont.woff2 Binary files differ diff --git a/src/assets/login/avatar.svg b/src/assets/login/avatar.svg new file mode 100644 index 0000000..a63d2b1 --- /dev/null +++ b/src/assets/login/avatar.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" class="icon" viewBox="0 0 1024 1024"><path fill="#386BF3" d="M410.558.109c0 210.974-300.876 361.752-300.876 633.548 0 174.943 134.704 316.787 300.876 316.787s300.877-141.817 300.877-316.787C711.408 361.752 410.558 210.974 410.558.109"/><path fill="#C3D2FB" d="M613.469 73.665c0 211.055-300.877 361.914-300.877 633.547C312.592 882.156 447.296 1024 613.47 1024s300.876-141.817 300.876-316.788C914.29 435.58 613.469 284.72 613.469 73.665"/><path fill="#303F5B" d="M312.592 707.212c0-183.713 137.636-312.171 226.723-441.39 81.702 106.112 172.12 218.74 172.12 367.726A309.755 309.755 0 0 1 420.36 950.064a323.1 323.1 0 0 1-107.769-242.852z"/></svg> \ No newline at end of file diff --git a/src/assets/login/bg.png b/src/assets/login/bg.png new file mode 100644 index 0000000..8cdd300 --- /dev/null +++ b/src/assets/login/bg.png Binary files differ diff --git a/src/assets/login/illustration.svg b/src/assets/login/illustration.svg new file mode 100644 index 0000000..b58ffd0 --- /dev/null +++ b/src/assets/login/illustration.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="500" height="380" viewBox="0 0 897.318 556.975"><path fill="#f2f2f2" d="m217.339 502.047.998-22.434a72.46 72.46 0 0 1 33.795-8.555c-16.231 13.27-14.203 38.85-25.207 56.696a43.58 43.58 0 0 1-31.96 20.14l-13.583 8.317a73.03 73.03 0 0 1 15.393-59.18 70.5 70.5 0 0 1 12.965-12.045c3.253 8.578 7.599 17.06 7.599 17.06"/><path fill="#cacaca" d="M796.921 36.552H164.598a1.016 1.016 0 0 1 0-2.03h632.324a1.016 1.016 0 0 1 0 2.03"/><ellipse cx="186.953" cy="11.169" fill="#3f3d56" rx="10.925" ry="11.169"/><ellipse cx="224.695" cy="11.169" fill="#3f3d56" rx="10.925" ry="11.169"/><ellipse cx="262.437" cy="11.169" fill="#3f3d56" rx="10.925" ry="11.169"/><path fill="#3f3d56" d="M774.304 2.768h-26.81a2.03 2.03 0 0 0 0 4.06h26.81a2.03 2.03 0 0 0 0-4.06m0 7.62h-26.81a2.03 2.03 0 0 0 0 4.06h26.81a2.03 2.03 0 0 0 0-4.06m0 7.61h-26.81a2.03 2.03 0 0 0 0 4.06h26.81a2.03 2.03 0 0 0 0-4.06m-117.591 98.143h-434.01a8.07 8.07 0 0 0-8.07 8.06v204.87a8.08 8.08 0 0 0 8.07 8.07h434.01a8.077 8.077 0 0 0 8.06-8.07v-204.87a8.07 8.07 0 0 0-8.06-8.06"/><path fill="#589ff8" d="M542.073 214.842a8.07 8.07 0 0 0-8.06 8.06v57.87a8.077 8.077 0 0 0 8.06 8.07h122.7v-74Z"/><path fill="#589ff8" d="M871.088 288.837h-329.01a8.076 8.076 0 0 1-8.067-8.066v-57.868a8.075 8.075 0 0 1 8.067-8.066h329.01a8.075 8.075 0 0 1 8.066 8.066v57.868a8.076 8.076 0 0 1-8.066 8.066" opacity=".5"/><circle cx="586.571" cy="255.537" r="13.089" fill="#fff"/><path fill="#fff" d="M860.894 251.734H624.38a3.898 3.898 0 1 1 0-7.796h236.514a3.898 3.898 0 1 1 0 7.796m-89.831 15.401H624.38a3.898 3.898 0 1 1 0-7.795h146.683a3.898 3.898 0 0 1 0 7.795"/><path fill="#ffb6b6" d="m151.406 545.537 11.328-.001 5.389-43.693h-16.719z"/><path fill="#2f2e41" d="M148.517 541.838h3.188l12.449-5.062 6.671 5.061h.001a14.22 14.22 0 0 1 14.217 14.217v.462l-36.526.001Z"/><path fill="#ffb6b6" d="m49.051 530.809 10.139 5.053 24.314-36.701-14.963-7.458z"/><path fill="#2f2e41" d="m48.115 526.21 2.854 1.422 13.4 1.022 3.712 7.507h.001a14.22 14.22 0 0 1 6.382 19.066l-.206.413-32.69-16.292Zm108.31-179.114-72.026 1.88 1.253 35.073s-1.253 9.395 1.252 11.9 3.758 2.505 2.506 6.89-4.491 46.273-4.491 46.273-29.562 52.27-28.31 53.522 2.506 0 1.253 3.132-2.505 1.879-1.252 3.132a46 46 0 0 1 3.131 3.757h20.416s1.142-6.263 1.142-6.889 1.252-4.384 1.252-5.01 35.67-38.418 35.67-38.418l7.515-62.631 18.163 61.378s0 53.863 1.253 55.116 1.252.626.626 3.132-3.132 1.878-1.253 3.757 2.505-1.252 1.88 1.88l-.627 3.13 24.062.27s2.506-5.28 1.253-7.159-1.178-1.366.35-4.44 2.155-3.702 1.529-4.328-.626-3.958-.626-3.958-9.031-123.183-9.031-125.062a6.25 6.25 0 0 1 .52-2.818v-2.55l-2.4-9.038Z"/><path fill="#589ff8" d="M869.68 238.348a27.638 27.638 0 1 1 27.638-27.638 27.64 27.64 0 0 1-27.638 27.638"/><path fill="#fff" d="M880.586 207.984h-8.18v-8.18a2.726 2.726 0 0 0-5.452 0v8.18h-8.179a2.726 2.726 0 1 0 0 5.452h8.18v8.18a2.726 2.726 0 0 0 5.452 0v-8.18h8.179a2.726 2.726 0 1 0 0-5.452"/><path fill="#589ff8" d="M447.883 289.212h-105.01a8.08 8.08 0 0 0-8.07 8.07v39.86h121.14v-39.86a8.077 8.077 0 0 0-8.06-8.07"/><path fill="#589ff8" d="M447.88 401.212H342.87a8.076 8.076 0 0 1-8.067-8.067v-95.867a8.075 8.075 0 0 1 8.067-8.067h105.01a8.075 8.075 0 0 1 8.066 8.067v95.867a8.076 8.076 0 0 1-8.066 8.067" opacity=".5"/><circle cx="373.808" cy="321.563" r="13.089" fill="#fff"/><path fill="#fff" d="M426.131 354.547h-61.514a3.898 3.898 0 1 1 0-7.795h61.514a3.898 3.898 0 1 1 0 7.795M394.3 369.95h-29.683a3.898 3.898 0 0 1 0-7.797H394.3a3.898 3.898 0 0 1 0 7.796"/><path fill="#589ff8" d="M340.68 429.348a27.638 27.638 0 1 1 27.638-27.638 27.64 27.64 0 0 1-27.638 27.638"/><path fill="#fff" d="M351.586 398.984h-8.18v-8.18a2.726 2.726 0 1 0-5.452 0v8.18h-8.179a2.726 2.726 0 1 0 0 5.452h8.18v8.18a2.726 2.726 0 1 0 5.452 0v-8.18h8.179a2.726 2.726 0 1 0 0-5.452"/><path fill="#589ff8" d="M327.887 228.266h-105.01a8.076 8.076 0 0 1-8.067-8.066v-95.867a8.075 8.075 0 0 1 8.067-8.067h105.01a8.075 8.075 0 0 1 8.066 8.067V220.2a8.076 8.076 0 0 1-8.066 8.066"/><circle cx="253.816" cy="156.618" r="13.089" fill="#589ff8"/><path fill="#589ff8" d="M306.139 185.602h-61.514a3.898 3.898 0 1 1 0-7.795h61.514a3.898 3.898 0 1 1 0 7.795m-31.831 15.402h-29.683a3.898 3.898 0 1 1 0-7.796h29.683a3.898 3.898 0 1 1 0 7.796"/><path fill="#589ff8" d="M327.887 228.266h-105.01a8.076 8.076 0 0 1-8.067-8.066v-95.867a8.075 8.075 0 0 1 8.067-8.067h105.01a8.075 8.075 0 0 1 8.066 8.067V220.2a8.076 8.076 0 0 1-8.066 8.066" opacity=".5"/><circle cx="253.816" cy="156.618" r="13.089" fill="#fff"/><path fill="#fff" d="M306.139 185.602h-61.514a3.898 3.898 0 1 1 0-7.795h61.514a3.898 3.898 0 1 1 0 7.795m-31.831 15.402h-29.683a3.898 3.898 0 1 1 0-7.796h29.683a3.898 3.898 0 1 1 0 7.796"/><circle cx="225.043" cy="115.951" r="21" fill="#ff6584"/><path fill="#ccc" d="M282.67 555.785a1.186 1.186 0 0 1-1.19 1.19H1.19a1.19 1.19 0 0 1 0-2.38h280.29a1.187 1.187 0 0 1 1.19 1.19"/><path fill="#ffb6b6" d="M220.555 171.576a9.77 9.77 0 0 1-5.759 12.435 9.6 9.6 0 0 1-1.635.451l-5.547 33.96-13.01-12.013 7.262-30.407a9.806 9.806 0 0 1 8.59-10.76 9.55 9.55 0 0 1 10.099 6.334"/><path fill="#3f3d56" d="M124.54 248.524s10.098-13.341 46.74-12.976l20.797-7.556 4.753-43.57 16.636 3.96-2.377 53.87-35.648 20.596-46.739 9.506Z"/><circle cx="119.175" cy="198.983" r="21.747" fill="#ffb6b6" data-name="ab6171fa-7d69-4734-b81c-8dff60f9761b"/><path fill="#3f3d56" d="M82.367 363.878a.4.4 0 0 1-.114-.016c-.401-.112-.719-.2.73-12.73l1.564-9.903-1.526-8.744-2.568-2.568 4.127-4.127 3.463-9.838-5.993-8.88-6.875-36.317a28.97 28.97 0 0 1 15.91-31.478l7.958-2.325 2.896-5.31a9.52 9.52 0 0 1 8.286-4.962l14.573-.11a9.52 9.52 0 0 1 7.617 3.716l5.084 6.609 21.082 7.161-3.495 75.322a5.233 5.233 0 0 1 .359 7.695c-.22.221-.393.401-.5.52-.356.505.31 4.275 1.134 7.475l1.056 4.902a3.013 3.013 0 0 0-.548 4.398l1.347 1.59a7.6 7.6 0 0 1-6.508 8.536c-19.267 2.622-68.958 9.384-69.059 9.384"/><path fill="#2f2e41" d="M113.612 219.665q-.14-.307-.278-.615c.036 0 .07.006.106.007Zm-16.789-41.441a6.05 6.05 0 0 1 3.792-1.64c1.406.046 2.832 1.316 2.54 2.693a22.35 22.35 0 0 1 26.896-10.085c3.495 1.233 6.922 3.7 7.725 7.318a6.6 6.6 0 0 0 .83 2.702 3.08 3.08 0 0 0 3.283.832l.034-.01a1.028 1.028 0 0 1 1.242 1.45l-.989 1.844a7.9 7.9 0 0 0 3.776-.08 1.027 1.027 0 0 1 1.09 1.598 17.9 17.9 0 0 1-14.269 7.334c-3.951-.024-7.943-1.386-11.789-.477a10.24 10.24 0 0 0-6.887 14.375c-1.182-1.292-3.466-.986-4.674.28a6.4 6.4 0 0 0-1.4 4.906 22.8 22.8 0 0 0 2.337 7.638 22.836 22.836 0 0 1-13.537-40.678"/><path fill="#ffb6b6" d="M90.84 395.068a9.77 9.77 0 0 1-2.303-13.509 9.6 9.6 0 0 1 1.092-1.298l-14.675-31.123 17.527 2.525 11.249 29.167a9.806 9.806 0 0 1-.98 13.733 9.55 9.55 0 0 1-11.91.505"/><path fill="#3f3d56" d="m86.395 378.074-23.352-52.483-.234-41.452 7.361-22.39a23.925 23.925 0 0 1 30.828-15.04l.162.058.068.158c.272.635 6.446 15.907-11.867 47.323l-3.686 21.496 12.933 49.274Z"/></svg> \ No newline at end of file diff --git a/src/assets/status/403.svg b/src/assets/status/403.svg new file mode 100644 index 0000000..ba3ce29 --- /dev/null +++ b/src/assets/status/403.svg @@ -0,0 +1 @@ +<svg width="251" height="294"><g fill="none"><path fill="#E4EBF7" d="M0 129.023v-2.084C0 58.364 55.591 2.774 124.165 2.774h2.085c68.574 0 124.165 55.59 124.165 124.165v2.084c0 68.575-55.59 124.166-124.165 124.166h-2.085C55.591 253.189 0 197.598 0 129.023"/><path fill="#FFF" d="M41.417 132.92a8.231 8.231 0 1 1-16.38-1.65 8.231 8.231 0 0 1 16.38 1.65"/><path stroke="#FFF" d="m38.652 136.36 10.425 5.91m.912 6.235-12.58 10.73"/><path fill="#FFF" d="M41.536 161.28a5.636 5.636 0 1 1-11.216-1.13 5.636 5.636 0 0 1 11.216 1.13m17.618-16.019a5.677 5.677 0 1 1-11.297-1.138 5.677 5.677 0 0 1 11.297 1.138M100.36 29.516l29.66-.013a4.562 4.562 0 1 0-.004-9.126l-29.66.013a4.563 4.563 0 0 0 .005 9.126m11.344 18.238 29.659-.013a4.563 4.563 0 1 0-.004-9.126l-29.66.013a4.563 4.563 0 1 0 .005 9.126"/><path fill="#FFF" d="M114.066 29.503V29.5l15.698-.007a4.563 4.563 0 1 0 .004 9.126l-15.698.007v-.002a4.562 4.562 0 0 0-.004-9.122m71.339 108.221c-.55 5.455-5.418 9.432-10.873 8.882-5.456-.55-9.432-5.418-8.882-10.873s5.418-9.432 10.873-8.882 9.432 5.418 8.882 10.873"/><path stroke="#FFF" d="m180.17 143.772 12.572 7.129m1.099 7.519-15.171 12.94"/><path fill="#FFF" d="M185.55 171.926a6.798 6.798 0 1 1-13.528-1.363 6.798 6.798 0 0 1 13.527 1.363m18.571-16.641a6.848 6.848 0 1 1-13.627-1.375 6.848 6.848 0 0 1 13.626 1.375"/><path stroke="#FFF" d="M152.988 194.074a2.21 2.21 0 1 1-4.42 0 2.21 2.21 0 0 1 4.42 0zm72.943-75.857a2.21 2.21 0 1 1-4.421 0 2.21 2.21 0 0 1 4.421 0zm-8.841 34.834a2.21 2.21 0 1 1-4.421 0 2.21 2.21 0 0 1 4.42 0zm-39.25-43.209a2.21 2.21 0 1 1-4.422 0 2.21 2.21 0 0 1 4.421 0zm18.274-15.388a2.21 2.21 0 1 1-4.421 0 2.21 2.21 0 0 1 4.421 0zm6.73 88.069a2.21 2.21 0 1 1-4.42 0 2.21 2.21 0 0 1 4.42 0z"/><path stroke="#FFF" d="m215.125 155.262-1.902 20.075-10.87 5.958m-27.752-4.659-6.322 9.761H156.98l-4.484 6.449m23.378-65.566v-15.72m45.636 7.844-12.77 7.859-15.228-7.86V96.668"/><path fill="#A26EF4" d="M180.68 29.32C180.68 13.128 193.806 0 210 0c16.193 0 29.32 13.127 29.32 29.32 0 16.194-13.127 29.322-29.32 29.322s-29.32-13.128-29.32-29.321"/><path fill="#FFF" d="m221.45 41.706-21.563-.125a1.744 1.744 0 0 1-1.734-1.754l.071-12.23a1.744 1.744 0 0 1 1.754-1.734l21.562.125c.964.006 1.74.791 1.735 1.755l-.071 12.229a1.744 1.744 0 0 1-1.754 1.734"/><path fill="#FFF" d="M215.106 29.192c-.015 2.577-2.049 4.654-4.543 4.64s-4.504-2.115-4.489-4.693l.04-6.925c.016-2.577 2.05-4.654 4.543-4.64s4.504 2.116 4.49 4.693l-.04 6.925zm-4.53-14.074a6.877 6.877 0 0 0-6.916 6.837l-.043 7.368a6.877 6.877 0 0 0 13.754.08l.042-7.368a6.88 6.88 0 0 0-6.837-6.917m-43.01 53.249h-3.93a4.73 4.73 0 0 1-4.717-4.717 4.73 4.73 0 0 1 4.717-4.717h3.93a4.73 4.73 0 0 1 4.717 4.717 4.73 4.73 0 0 1-4.717 4.717"/><path fill="#5BA02E" d="M168.214 248.838a6.61 6.61 0 0 1-6.61-6.611v-66.108a6.611 6.611 0 0 1 13.221 0v66.108a6.61 6.61 0 0 1-6.61 6.61"/><path fill="#92C110" d="M176.147 248.176a6.61 6.61 0 0 1-6.61-6.61v-33.054a6.611 6.611 0 1 1 13.221 0v33.053a6.61 6.61 0 0 1-6.61 6.611"/><path fill="#F2D7AD" d="M185.994 293.89h-27.376a3.17 3.17 0 0 1-3.17-3.17v-45.887a3.17 3.17 0 0 1 3.17-3.17h27.376a3.17 3.17 0 0 1 3.17 3.17v45.886a3.17 3.17 0 0 1-3.17 3.17"/><path fill="#FFF" d="M81.972 147.673s6.377-.927 17.566-1.28c11.729-.371 17.57 1.086 17.57 1.086s3.697-3.855.968-8.424c1.278-12.077 5.982-32.827.335-48.273-1.116-1.339-3.743-1.512-7.536-.62-1.337.315-7.147-.149-7.983-.1l-15.311-.347s-3.487-.17-8.035-.508c-1.512-.113-4.227-1.683-5.458-.338-.406.443-2.425 5.669-1.97 16.077l8.635 35.642s-3.141 3.61 1.219 7.085"/><path fill="#FFC6A0" d="m75.768 73.325-.9-6.397 11.982-6.52s7.302-.118 8.038 1.205c.737 1.324-5.616.993-5.616.993s-1.836 1.388-2.615 2.5c-1.654 2.363-.986 6.471-8.318 5.986-1.708.284-2.57 2.233-2.57 2.233"/><path fill="#FFB594" d="M52.44 77.672s14.217 9.406 24.973 14.444c1.061.497-2.094 16.183-11.892 11.811-7.436-3.318-20.162-8.44-21.482-14.496-.71-3.258 2.543-7.643 8.401-11.76m89.422 2.442s-6.693 2.999-13.844 6.876c-3.894 2.11-10.137 4.704-12.33 7.988-6.224 9.314 3.536 11.22 12.947 7.503 6.71-2.651 28.999-12.127 13.227-22.367"/><path fill="#FFC6A0" d="m76.166 66.36 3.06 3.881s-2.783 2.67-6.31 5.747c-7.103 6.195-12.803 14.296-15.995 16.44-3.966 2.662-9.754 3.314-12.177-.118-3.553-5.032.464-14.628 31.422-25.95"/><path fill="#FFF" d="M64.674 85.116s-2.34 8.413-8.912 14.447c.652.548 18.586 10.51 22.144 10.056 5.238-.669 6.417-18.968 1.145-20.531-.702-.208-5.901-1.286-8.853-2.167-.87-.26-1.611-1.71-3.545-.936l-1.98-.869zm63.688.71s5.318 1.956 7.325 13.734c-.546.274-17.55 12.35-21.829 7.805-6.534-6.94-.766-17.393 4.275-18.61 4.646-1.121 5.03-1.37 10.23-2.929"/><path stroke="#E4EBF7" d="M78.18 94.656s.911 7.41-4.914 13.078M87.397 94.68s3.124 2.572 10.263 2.572c7.14 0 9.074-3.437 9.074-3.437"/><path fill="#FFC6A0" d="m117.184 68.639-6.781-6.177s-5.355-4.314-9.223-.893c-3.867 3.422 4.463 2.083 5.653 4.165s.848 1.143-2.083.446c-5.603-1.331-2.082.893 2.975 5.355 2.091 1.845 6.992.955 6.992.955z"/><path fill="#FFB594" d="m105.282 91.315-.297-10.937-15.918-.027-.53 10.45c-.026.403.17.788.515.999 2.049 1.251 9.387 5.093 15.799.424.287-.21.443-.554.431-.91"/><path fill="#5C2552" d="M107.573 74.24c.817-1.147.982-9.118 1.015-11.928a1.046 1.046 0 0 0-.965-1.055l-4.62-.365c-7.71-1.044-17.071.624-18.253 6.346-5.482 5.813-.421 13.244-.421 13.244s1.963 3.566 4.305 6.791c.756 1.041.398-3.731 3.04-5.929 5.524-4.594 15.899-7.103 15.899-7.103"/><path fill="#FFC6A0" d="M88.426 83.206s2.685 6.202 11.602 6.522c7.82.28 8.973-7.008 7.434-17.505l-.909-5.483c-6.118-2.897-15.478.54-15.478.54s-.576 2.044-.19 5.504c-2.276 2.066-1.824 5.618-1.824 5.618s-.905-1.922-1.98-2.321c-.86-.32-1.897.089-2.322 1.98-1.04 4.632 3.667 5.145 3.667 5.145"/><path stroke="#DB836E" d="m100.843 77.099 1.701-.928-1.015-4.324.674-1.406"/><path fill="#552950" d="M105.546 74.092c-.022.713-.452 1.279-.96 1.263-.51-.016-.904-.607-.882-1.32.021-.713.452-1.278.96-1.263.51.016.904.607.882 1.32m-7.954.257c-.022.713-.452 1.278-.961 1.263s-.904-.607-.882-1.32.452-1.279.961-1.263c.51.016.904.606.882 1.32"/><path stroke="#DB836E" d="M91.132 86.786s5.269 4.957 12.679 2.327"/><path fill="#DB836E" d="M99.776 81.903s-3.592.232-1.44-2.79c1.59-1.496 4.897-.46 4.897-.46s1.156 3.906-3.457 3.25"/><path stroke="#5C2552" d="M102.88 70.6s2.483.84 3.402.715m-12.399.66s2.492-1.144 4.778-1.073"/><path stroke="#DB836E" d="M86.32 77.374s.961.879 1.458 2.106c-.377.48-1.033 1.152-.236 1.809m11.795 2.43s1.911.151 2.509-.254"/><path stroke="#E4EBF7" d="m87.782 115.821 15.73-3.012m-3.347 3.012 10.04-2.008m-43.697-27.05s-1.598 8.83-6.697 14.078m68.499-12.907s3.013 4.121 4.06 11.785"/><path stroke="#DB836E" d="M64.09 84.816s-6.03 9.912-13.607 9.903"/><path fill="#FFC6A0" d="m112.366 65.909-.142 5.32s5.993 4.472 11.945 9.202c4.482 3.562 8.888 7.455 10.985 8.662 4.804 2.766 8.9 3.355 11.076 1.808 4.071-2.894 4.373-9.878-8.136-15.263-4.271-1.838-16.144-6.36-25.728-9.73"/><path stroke="#DB836E" d="M130.532 85.488s4.588 5.757 11.619 6.214"/><path stroke="#E4EBF7" d="M121.708 105.73s-.393 8.564-1.34 13.612"/><path stroke="#648BD8" d="M115.784 161.512s-3.57-1.488-2.678-7.14"/><path fill="#CBD1D1" d="M101.52 290.246s4.326 2.057 7.408 1.03c2.842-.948 4.564.673 7.132 1.186 2.57.514 6.925 1.108 11.772-1.269-.104-5.551-6.939-4.01-12.048-6.763-2.582-1.39-3.812-4.757-3.625-8.863h-9.471s-1.402 10.596-1.169 14.68"/><path fill="#2B0849" d="M101.496 290.073s2.447 1.281 6.809.658c3.081-.44 3.74.485 7.479 1.039s10.802-.07 11.91-.9c.415 1.108-.347 2.077-.347 2.077s-1.523.608-4.847.831c-2.045.137-5.843.293-7.663-.507-1.8-1.385-5.286-1.917-5.77-.243-3.947.958-7.41-.288-7.41-.288l-.16-2.667z"/><path fill="#A4AABA" d="M108.824 276.19h3.116s-.103 6.751 4.57 8.62c-4.673.624-8.62-2.32-7.686-8.62"/><path fill="#CBD1D1" d="M57.65 272.52s-2.122 7.47-4.518 12.396c-1.811 3.724-4.255 7.548 5.505 7.548 6.698 0 9.02-.483 7.479-6.648-1.541-6.164.268-13.296.268-13.296z"/><path fill="#2B0849" d="M51.54 290.04s2.111 1.178 6.682 1.178c6.128 0 8.31-1.662 8.31-1.662s.605 1.122-.624 2.18c-1 .862-3.624 1.603-7.444 1.559-4.177-.049-5.876-.57-6.786-1.177-.831-.554-.692-1.593-.138-2.078"/><path fill="#A4AABA" d="M58.533 274.438s.034 1.529-.315 2.95c-.352 1.431-1.087 3.127-1.139 4.17-.058 1.16 4.57 1.592 5.194.035.623-1.559 1.303-6.475 1.927-7.306.622-.831-4.94-2.135-5.667.15"/><path fill="#7BB2F9" d="m100.885 277.015 13.306.092s1.291-54.228 1.843-64.056 3.756-43.13.997-62.788l-12.48-.64-22.725.776s-.433 3.944-1.19 9.921c-.062.493-.677.838-.744 1.358-.075.582.42 1.347.318 1.956-2.35 14.003-6.343 32.926-8.697 46.425-.116.663-1.227 1.004-1.45 2.677-.04.3.21 1.516.112 1.785-6.836 18.643-10.89 47.584-14.2 61.551l14.528-.014s2.185-8.524 4.008-16.878c2.796-12.817 22.987-84.553 22.987-84.553l3-.517 1.037 46.1s-.223 1.228.334 2.008c.558.782-.556 1.117-.39 2.233l.39 1.784s-.446 7.14-.892 11.826c-.446 4.685-.092 38.954-.092 38.954"/><path stroke="#648BD8" d="M77.438 220.434c1.146.094 4.016-2.008 6.916-4.91m23.196 8.407s2.758-1.103 6.069-3.862m-5.16.836s2.759-1.104 6.07-3.863m-38.43 6.515s2.608-.587 6.47-3.346m4.761-69.391c-.27 3.088.297 8.478-4.315 9.073m21.814-10.818s.11 13.936-1.286 14.983c-2.207 1.655-2.975 1.934-2.975 1.934m.446-16.362s.035 12.81-1.19 24.245m-4.894 1.09s7.174-1.655 9.38-1.655m-28.639 31.444c-.316 1.55-.64 3.067-.973 4.535 0 0-1.45 1.822-1.003 3.756.446 1.934-.943 2.034-4.96 15.273-1.686 5.559-4.464 18.49-6.313 27.447-.078.38-4.018 18.06-4.093 18.423m18.714-77.445a313 313 0 0 1-.877 4.729m7.742-50.058-1.19 10.413s-1.091.148-.496 2.23c.111 1.34-2.66 15.692-5.153 30.267M57.58 272.94h13.238"/><path fill="#192064" d="M117.377 147.423s-16.955-3.087-35.7.199c.157 2.501-.002 4.128-.002 4.128s14.607-2.802 35.476-.31c.251-2.342.226-4.017.226-4.017"/><path fill="#FFF" d="m107.511 150.353.004-4.885a.807.807 0 0 0-.774-.81c-2.428-.092-5.04-.108-7.795-.014a.814.814 0 0 0-.784.81l-.003 4.88c0 .456.371.82.827.808a141 141 0 0 1 7.688.017.81.81 0 0 0 .837-.806"/><path fill="#192064" d="m106.402 149.426.002-3.06a.64.64 0 0 0-.616-.643 94 94 0 0 0-5.834-.009.647.647 0 0 0-.626.643l-.001 3.056c0 .36.291.648.651.64 1.78-.04 3.708-.041 5.762.012a.644.644 0 0 0 .662-.64"/><path stroke="#648BD8" d="M101.485 273.933h12.272m-11.105-4.858c.006 3.368.04 5.759.11 6.47m-.095-12.42c-.009 1.53-.015 2.98-.016 4.313m-.447-93.414.893 44.402s.669 1.561-.224 2.677c-.892 1.116 2.455.67.893 2.231-1.562 1.562.893 1.116 0 3.347-.592 1.48-.988 20.987-1.09 34.956"/></g></svg> \ No newline at end of file diff --git a/src/assets/status/404.svg b/src/assets/status/404.svg new file mode 100644 index 0000000..aacb740 --- /dev/null +++ b/src/assets/status/404.svg @@ -0,0 +1 @@ +<svg width="252" height="294"><g fill="none"><path fill="#E4EBF7" d="M0 127.32v-2.095C0 56.279 55.892.387 124.838.387h2.096c68.946 0 124.838 55.892 124.838 124.838v2.096c0 68.946-55.892 124.838-124.838 124.838h-2.096C55.892 252.16 0 196.267 0 127.321" mask="url(#b)" transform="translate(0 .012)"/><path fill="#FFF" d="M39.755 130.84a8.276 8.276 0 1 1-16.468-1.66 8.276 8.276 0 0 1 16.468 1.66"/><path stroke="#FFF" d="m36.975 134.297 10.482 5.943m.916 6.268-12.648 10.788"/><path fill="#FFF" d="M39.875 159.352a5.667 5.667 0 1 1-11.277-1.136 5.667 5.667 0 0 1 11.277 1.136m17.713-16.105a5.708 5.708 0 1 1-11.358-1.145 5.708 5.708 0 0 1 11.358 1.145m41.43-116.372 29.82-.014a4.587 4.587 0 1 0-.003-9.175l-29.82.013a4.587 4.587 0 1 0 .003 9.176m11.406 18.336 29.82-.013a4.588 4.588 0 0 0-.004-9.175l-29.82.013a4.587 4.587 0 1 0 .004 9.175"/><path fill="#FFF" d="M112.798 26.861v-.002l15.784-.006a4.588 4.588 0 1 0 .003 9.175l-15.783.007v-.002a4.586 4.586 0 0 0-.004-9.172m71.725 108.807c-.553 5.485-5.447 9.483-10.931 8.93-5.485-.553-9.483-5.448-8.93-10.932.552-5.485 5.447-9.483 10.932-8.93s9.483 5.447 8.93 10.932"/><path stroke="#FFF" d="m179.26 141.75 12.64 7.167m1.106 7.56-15.255 13.011"/><path fill="#FFF" d="M184.668 170.057a6.835 6.835 0 1 1-13.6-1.372 6.835 6.835 0 0 1 13.6 1.372m18.672-16.732a6.885 6.885 0 1 1-13.7-1.382 6.885 6.885 0 0 1 13.7 1.382"/><path stroke="#FFF" d="M151.931 192.324a2.222 2.222 0 1 1-4.444 0 2.222 2.222 0 0 1 4.444 0zm73.339-76.268a2.222 2.222 0 1 1-4.445 0 2.222 2.222 0 0 1 4.444 0zm-8.89 35.024a2.223 2.223 0 1 1-4.446-.001 2.223 2.223 0 0 1 4.446 0zm-39.463-43.444a2.223 2.223 0 1 1-4.445 0 2.223 2.223 0 0 1 4.445 0zm18.374-15.471a2.223 2.223 0 1 1-4.445 0 2.223 2.223 0 0 1 4.445 0zm6.767 88.546a2.223 2.223 0 1 1-4.446 0 2.223 2.223 0 0 1 4.446 0z"/><path stroke="#FFF" d="m214.404 153.302-1.912 20.184-10.928 5.99m-27.903-4.684-6.356 9.814h-11.36l-4.508 6.484m23.504-65.922v-15.804m45.883 7.886-12.84 7.901-15.31-7.902V94.39"/><path fill="#FFF" d="M166.588 65.936h-3.951a4.756 4.756 0 0 1-4.743-4.742 4.756 4.756 0 0 1 4.743-4.743h3.951a4.756 4.756 0 0 1 4.743 4.743 4.756 4.756 0 0 1-4.743 4.742"/><path fill="#1890FF" d="M174.823 30.03c0-16.281 13.198-29.48 29.48-29.48 16.28 0 29.48 13.199 29.48 29.48s-13.2 29.48-29.48 29.48c-16.282 0-29.48-13.2-29.48-29.48"/><path fill="#FFF" d="M205.952 38.387c.5.5.785 1.142.785 1.928s-.286 1.465-.785 1.964a2.9 2.9 0 0 1-2 .75c-.785 0-1.429-.285-1.929-.785-.572-.5-.82-1.143-.82-1.929s.248-1.428.82-1.928q.75-.75 1.93-.75c.785 0 1.462.25 1.999.75m4.285-19.463q2.143 1.874 2.143 5.142c0 1.712-.427 3.13-1.219 4.25-.067.096-.137.18-.218.265-.416.429-1.41 1.346-2.956 2.699a5.1 5.1 0 0 0-1.428 1.75 5.2 5.2 0 0 0-.536 2.357v.5h-4.107v-.5c0-1.357.215-2.536.714-3.5.464-.964 1.857-2.464 4.178-4.536l.43-.5c.643-.785.964-1.643.964-2.535 0-1.18-.358-2.108-1-2.785-.678-.68-1.643-1.001-2.858-1.001-1.536 0-2.642.464-3.357 1.43q-.553.75-.76 1.904a2 2 0 0 1-1.971 1.63h-.004c-1.277 0-2.257-1.183-1.98-2.43.337-1.518 1.02-2.78 2.073-3.784 1.536-1.5 3.607-2.25 6.25-2.25 2.32 0 4.214.607 5.642 1.894"/><path fill="#FFB594" d="M52.04 76.131s21.81 5.36 27.307 15.945c5.575 10.74-6.352 9.26-15.73 4.935-10.86-5.008-24.7-11.822-11.577-20.88"/><path fill="#FFC6A0" d="m90.483 67.504-.449 2.893c-.753.49-4.748-2.663-4.748-2.663l-1.645.748-1.346-5.684s6.815-4.589 8.917-5.018c2.452-.501 9.884.94 10.7 2.278 0 0 1.32.486-2.227.69-3.548.203-5.043.447-6.79 3.132s-2.412 3.624-2.412 3.624"/><path fill="#FFF" d="M128.055 111.367c-2.627-7.724-6.15-13.18-8.917-15.478-3.5-2.906-9.34-2.225-11.366-4.187-1.27-1.231-3.215-1.197-3.215-1.197s-14.98-3.158-16.828-3.479c-2.37-.41-2.124-.714-6.054-1.405-1.57-1.907-2.917-1.122-2.917-1.122l-7.11-1.383c-.853-1.472-2.423-1.023-2.423-1.023l-2.468-.897c-1.645 9.976-7.74 13.796-7.74 13.796 1.795 1.122 15.703 8.3 15.703 8.3l5.107 37.11s-3.321 5.694 1.346 9.109c0 0 19.883-3.743 34.921-.329 0 0 3.047-2.546.972-8.806.523-3.01 1.394-8.263 1.736-11.622.385.772 2.019 1.918 3.14 3.477 0 0 9.407-7.365 11.052-14.012-.832-.723-1.598-1.585-2.267-2.453-.567-.736-.358-2.056-.765-2.717-.669-1.084-1.804-1.378-1.907-1.682"/><path fill="#CBD1D1" d="M101.09 289.998s4.295 2.041 7.354 1.021c2.821-.94 4.53.668 7.08 1.178s6.874 1.1 11.686-1.26c-.103-5.51-6.889-3.98-11.96-6.713-2.563-1.38-3.784-4.722-3.598-8.799h-9.402s-1.392 10.52-1.16 14.573"/><path fill="#2B0849" d="M101.067 289.826s2.428 1.271 6.759.653c3.058-.437 3.712.481 7.423 1.031 3.712.55 10.724-.069 11.823-.894.413 1.1-.343 2.063-.343 2.063s-1.512.603-4.812.824c-2.03.136-5.8.291-7.607-.503-1.787-1.375-5.247-1.903-5.728-.241-3.918.95-7.355-.286-7.355-.286z"/><path fill="#A4AABA" d="M108.341 276.044h3.094s-.103 6.702 4.536 8.558c-4.64.618-8.558-2.303-7.63-8.558"/><path fill="#CBD1D1" d="M57.542 272.401s-2.107 7.416-4.485 12.306c-1.798 3.695-4.225 7.492 5.465 7.492 6.648 0 8.953-.48 7.423-6.599-1.53-6.12.266-13.199.266-13.199z"/><path fill="#2B0849" d="M51.476 289.793s2.097 1.169 6.633 1.169c6.083 0 8.249-1.65 8.249-1.65s.602 1.114-.619 2.165c-.993.855-3.597 1.591-7.39 1.546-4.145-.048-5.832-.566-6.736-1.168-.825-.55-.687-1.58-.137-2.062"/><path fill="#A4AABA" d="M58.419 274.304s.033 1.519-.314 2.93c-.349 1.42-1.078 3.104-1.13 4.139-.058 1.151 4.537 1.58 5.155.034.62-1.547 1.294-6.427 1.913-7.252s-4.903-2.119-5.624.15"/><path fill="#7BB2F9" d="m99.66 278.514 13.378.092s1.298-54.52 1.853-64.403c.554-9.882 3.776-43.364 1.002-63.128l-12.547-.644-22.849.78s-.434 3.966-1.195 9.976c-.063.496-.682.843-.749 1.365-.075.585.423 1.354.32 1.966-2.364 14.08-6.377 33.104-8.744 46.677-.116.666-1.234 1.009-1.458 2.691-.04.302.211 1.525.112 1.795-6.873 18.744-10.949 47.842-14.277 61.885l14.607-.014s2.197-8.57 4.03-16.97c2.811-12.886 23.111-85.01 23.111-85.01l3.016-.521 1.043 46.35s-.224 1.234.337 2.02c.56.785-.56 1.123-.392 2.244l.392 1.794s-.449 7.178-.898 11.89c-.448 4.71-.092 39.165-.092 39.165"/><path stroke="#648BD8" d="M76.085 221.626c1.153.094 4.038-2.019 6.955-4.935m23.32 8.451s2.774-1.11 6.103-3.883m-5.188.841s2.773-1.11 6.102-3.884m-38.637 6.551s2.622-.591 6.505-3.365m4.785-69.768c-.27 3.106.3 8.525-4.336 9.123m21.931-10.877s.11 14.012-1.293 15.065c-2.219 1.664-2.99 1.944-2.99 1.944m.448-16.451s.035 12.88-1.196 24.377m-4.921 1.096s7.212-1.664 9.431-1.664M74.31 205.861a212 212 0 0 1-.979 4.56s-1.458 1.832-1.009 3.776-.947 2.045-4.985 15.355c-1.696 5.59-4.49 18.591-6.348 27.597l-.231 1.12m14.931-60.462a321 321 0 0 1-.882 4.754m7.784-50.328L81.395 162.7s-1.097.15-.5 2.244c.113 1.346-2.674 15.775-5.18 30.43M56.12 274.418h13.31"/><path fill="#192064" d="M116.241 148.22s-17.047-3.104-35.893.2c.158 2.514-.003 4.15-.003 4.15s14.687-2.818 35.67-.312c.252-2.355.226-4.038.226-4.038"/><path fill="#FFF" d="m106.322 151.165.003-4.911a.81.81 0 0 0-.778-.815 110 110 0 0 0-7.836-.014.82.82 0 0 0-.789.815l-.003 4.906a.81.81 0 0 0 .831.813c2.385-.06 4.973-.064 7.73.017a.815.815 0 0 0 .842-.81"/><path fill="#192064" d="m105.207 150.233.002-3.076a.64.64 0 0 0-.619-.646 94 94 0 0 0-5.866-.01.65.65 0 0 0-.63.647v3.072a.64.64 0 0 0 .654.644 121 121 0 0 1 5.794.011c.362.01.665-.28.665-.642"/><path stroke="#648BD8" d="M100.263 275.415h12.338m-11.165-4.885c.006 3.387.042 5.79.111 6.506m-.096-12.488a916 916 0 0 0-.015 4.337m-.45-93.92.898 44.642s.673 1.57-.225 2.692c-.897 1.122 2.468.673.898 2.243s.897 1.122 0 3.365c-.596 1.489-.994 21.1-1.096 35.146"/><path fill="#FFC6A0" d="M46.876 83.427s-.516 6.045 7.223 5.552c11.2-.712 9.218-9.345 31.54-21.655-.786-2.708-2.447-4.744-2.447-4.744s-11.068 3.11-22.584 8.046c-6.766 2.9-13.395 6.352-13.732 12.801m57.584 7.63.941-5.372-8.884-11.43-5.037 5.372-1.74 7.834a.32.32 0 0 0 .108.32c.965.8 6.5 5.013 14.347 3.544a.33.33 0 0 0 .264-.268"/><path fill="#FFC6A0" d="M93.942 79.387s-4.533-2.853-2.432-6.855c1.623-3.09 4.513 1.133 4.513 1.133s.52-3.642 3.121-3.642c.52-1.04 1.561-4.162 1.561-4.162s11.445 2.601 13.526 3.121c0 5.203-2.304 19.424-7.84 19.861-8.892.703-12.449-9.456-12.449-9.456"/><path fill="#520038" d="M113.874 73.446c2.601-2.081 3.47-9.722 3.47-9.722s-2.479-.49-6.64-2.05c-4.683-2.081-12.798-4.747-17.48.976-9.668 3.223-2.05 19.823-2.05 19.823l2.713-3.021s-3.935-3.287-2.08-6.243c2.17-3.462 3.92 1.073 3.92 1.073s.637-2.387 3.581-3.342c.355-.71 1.036-2.674 1.432-3.85a1.073 1.073 0 0 1 1.263-.704c2.4.558 8.677 2.019 11.356 2.662.522.125.871.615.82 1.15z"/><path fill="#552950" d="M104.977 76.064c-.103.61-.582 1.038-1.07.956s-.801-.644-.698-1.254.582-1.038 1.07-.956.8.644.698 1.254m7.155 1.63c-.103.61-.582 1.038-1.07.956s-.8-.644-.698-1.254.582-1.038 1.07-.956.8.643.698 1.254"/><path stroke="#DB836E" d="m110.13 74.84-.896 1.61-.298 4.357h-2.228"/><path stroke="#5C2552" d="M110.846 74.481s1.79-.716 2.506.537"/><path stroke="#DB836E" d="M92.386 74.282s.477-1.114 1.113-.716c.637.398 1.274 1.433.558 1.99-.717.556.159 1.67.159 1.67"/><path stroke="#5C2552" d="M103.287 72.93s1.83 1.113 4.137.954"/><path stroke="#DB836E" d="M103.685 81.762s2.227 1.193 4.376 1.193m-3.421 1.353s.954.398 1.511.318m-11.458-3.421s2.308 7.4 10.424 7.639"/><path stroke="#E4EBF7" d="M81.45 89.384s.45 5.647-4.935 12.787M69 82.654s-.726 9.282-8.204 14.206m68.609 26.005s-5.272 7.403-9.422 10.768m-.677-26.304s.452 4.366-2.127 32.062"/><path fill="#F2D7AD" d="M150.028 151.232h-49.837a1.01 1.01 0 0 1-1.01-1.01v-31.688c0-.557.452-1.01 1.01-1.01h49.837c.558 0 1.01.453 1.01 1.01v31.688a1.01 1.01 0 0 1-1.01 1.01"/><path fill="#F4D19D" d="M150.29 151.232h-19.863v-33.707h20.784v32.786a.92.92 0 0 1-.92.92"/><path fill="#F2D7AD" d="M123.554 127.896H92.917a.518.518 0 0 1-.425-.816l6.38-9.113c.193-.277.51-.442.85-.442h31.092z"/><path fill="#CC9B6E" d="M123.689 128.447H99.25v-.519h24.169l7.183-10.26.424.298z"/><path fill="#F4D19D" d="M158.298 127.896h-18.669a2.07 2.07 0 0 1-1.659-.83l-7.156-9.541h19.965c.49 0 .95.23 1.244.622l6.69 8.92a.519.519 0 0 1-.415.83"/><path fill="#CC9B6E" d="M157.847 128.479h-19.384l-7.857-10.475.415-.31 7.7 10.266h19.126zm-27.293 22.206-.032-8.177.519-.002.032 8.177z"/><path fill="#CC9B6E" d="m130.511 139.783-.08-21.414.519-.002.08 21.414zm-18.635 1.149-.498-.143 1.479-5.167.498.143zm-3.439.128-2.679-2.935 2.665-3.434.41.318-2.397 3.089 2.384 2.612zm8.17 0-.383-.35 2.383-2.612-2.397-3.089.41-.318 2.665 3.434z"/><path fill="#FFC6A0" d="m154.316 131.892-3.114-1.96.038 3.514-1.043.092c-1.682.115-3.634.23-4.789.23-1.902 0-2.693 2.258 2.23 2.648l-2.645-.596s-2.168 1.317.504 2.3c0 0-1.58 1.217.561 2.58-.584 3.504 5.247 4.058 7.122 3.59 1.876-.47 4.233-2.359 4.487-5.16.28-3.085-.89-5.432-3.35-7.238"/><path stroke="#DB836E" d="M153.686 133.577s-6.522.47-8.36.372c-1.836-.098-1.904 2.19 2.359 2.264 3.739.15 5.451-.044 5.451-.044"/><path stroke="#DB836E" d="M145.16 135.877c-1.85 1.346.561 2.355.561 2.355s3.478.898 6.73.617"/><path stroke="#DB836E" d="M151.89 141.71s-6.28.111-6.73-2.132c-.223-1.346.45-1.402.45-1.402m.504 2.692s-1.103 3.16 5.44 3.533m-.352-14.469v3.477M52.838 89.286c3.533-.337 8.423-1.248 13.582-7.754"/><path fill="#5BA02E" d="M168.567 248.318a6.647 6.647 0 0 1-6.647-6.647v-66.466a6.647 6.647 0 1 1 13.294 0v66.466a6.647 6.647 0 0 1-6.647 6.647"/><path fill="#92C110" d="M176.543 247.653a6.647 6.647 0 0 1-6.646-6.647v-33.232a6.647 6.647 0 1 1 13.293 0v33.232a6.647 6.647 0 0 1-6.647 6.647"/><path fill="#F2D7AD" d="M186.443 293.613H158.92a3.187 3.187 0 0 1-3.187-3.187v-46.134a3.187 3.187 0 0 1 3.187-3.187h27.524a3.187 3.187 0 0 1 3.187 3.187v46.134a3.187 3.187 0 0 1-3.187 3.187"/><path stroke="#E4EBF7" d="M88.979 89.48s7.776 5.384 16.6 2.842"/></g></svg> \ No newline at end of file diff --git a/src/assets/status/500.svg b/src/assets/status/500.svg new file mode 100644 index 0000000..ea23a37 --- /dev/null +++ b/src/assets/status/500.svg @@ -0,0 +1 @@ +<svg width="254" height="294"><g fill="none"><path fill="#E4EBF7" d="M0 128.134v-2.11C0 56.608 56.273.334 125.69.334h2.11c69.416 0 125.69 56.274 125.69 125.69v2.11c0 69.417-56.274 125.69-125.69 125.69h-2.11C56.273 253.824 0 197.551 0 128.134" mask="url(#b)" transform="translate(0 .067)"/><path fill="#FFF" d="M39.989 132.108a8.332 8.332 0 1 1-16.581-1.671 8.332 8.332 0 0 1 16.58 1.671"/><path stroke="#FFF" d="m37.19 135.59 10.553 5.983m.922 6.311-12.734 10.861"/><path fill="#FFF" d="M40.11 160.816a5.706 5.706 0 1 1-11.354-1.145 5.706 5.706 0 0 1 11.354 1.145M57.943 144.6a5.747 5.747 0 1 1-11.436-1.152 5.747 5.747 0 0 1 11.436 1.153M99.656 27.434l30.024-.013a4.619 4.619 0 1 0-.004-9.238l-30.024.013a4.62 4.62 0 0 0 .004 9.238m11.484 18.462 30.023-.013a4.62 4.62 0 1 0-.004-9.238l-30.024.013a4.619 4.619 0 1 0 .004 9.238"/><path fill="#FFF" d="M113.53 27.421v-.002l15.89-.007a4.619 4.619 0 1 0 .005 9.238l-15.892.007v-.002a4.618 4.618 0 0 0-.004-9.234m36.638 42.67h-3.979a4.79 4.79 0 0 1-4.774-4.775 4.79 4.79 0 0 1 4.774-4.774h3.979a4.79 4.79 0 0 1 4.775 4.774 4.79 4.79 0 0 1-4.775 4.775"/><path fill="#FF603B" d="M171.687 30.234c0-16.392 13.289-29.68 29.681-29.68s29.68 13.288 29.68 29.68c0 16.393-13.288 29.681-29.68 29.681s-29.68-13.288-29.68-29.68"/><path fill="#FFF" d="m203.557 19.435-.676 15.035a1.514 1.514 0 0 1-3.026 0l-.675-15.035a2.19 2.19 0 1 1 4.377 0m-.264 19.378q.77.715.77 1.87c0 1.155-.257 1.393-.77 1.907-.55.476-1.21.733-1.943.733a2.55 2.55 0 0 1-1.87-.77c-.55-.514-.806-1.136-.806-1.87 0-.77.256-1.393.806-1.87.513-.513 1.137-.733 1.87-.733.77 0 1.43.22 1.943.733"/><path fill="#FFB594" d="M119.3 133.275c4.426-.598 3.612-1.204 4.079-4.778.675-5.18-3.108-16.935-8.262-25.118-1.088-10.72-12.598-11.24-12.598-11.24s4.312 4.895 4.196 16.199c1.398 5.243.804 14.45.804 14.45s5.255 11.369 11.78 10.487"/><path fill="#FFF" d="M100.944 91.61s1.463-.583 3.211.582c8.08 1.398 10.368 6.706 11.3 11.368 1.864 1.282 1.864 2.33 1.864 3.496.365.777 1.515 3.03 1.515 3.03s-7.225 1.748-10.954 6.758c-1.399-6.41-6.936-25.235-6.936-25.235"/><path fill="#FFB594" d="m94.008 90.5 1.019-5.815-9.23-11.874-5.233 5.581-2.593 9.863s8.39 5.128 16.037 2.246"/><path fill="#FFC6A0" d="M82.931 78.216s-4.557-2.868-2.445-6.892c1.632-3.107 4.537 1.139 4.537 1.139s.524-3.662 3.139-3.662c.523-1.046 1.569-4.184 1.569-4.184s11.507 2.615 13.6 3.138c-.001 5.23-2.317 19.529-7.884 19.969-8.94.706-12.516-9.508-12.516-9.508"/><path fill="#520038" d="M102.971 72.243c2.616-2.093 3.489-9.775 3.489-9.775s-2.492-.492-6.676-2.062c-4.708-2.092-12.867-4.771-17.575.982-9.54 4.41-2.062 19.93-2.062 19.93l2.729-3.037s-3.956-3.304-2.092-6.277c2.183-3.48 3.943 1.08 3.943 1.08s.64-2.4 3.6-3.36c.356-.714 1.04-2.69 1.44-3.872a1.08 1.08 0 0 1 1.27-.707c2.41.56 8.723 2.03 11.417 2.676.524.126.876.619.825 1.156z"/><path fill="#552950" d="M101.22 76.514c-.104.613-.585 1.044-1.076.96-.49-.082-.805-.646-.702-1.26.104-.613.585-1.044 1.076-.961s.805.647.702 1.26m-6.96-1.439c-.104.613-.585 1.044-1.076.96-.49-.082-.805-.646-.702-1.26.104-.613.585-1.044 1.076-.96.491.082.805.646.702 1.26"/><path stroke="#DB836E" d="m99.206 73.644-.9 1.62-.3 4.38h-2.24"/><path stroke="#5C2552" d="M99.926 73.284s1.8-.72 2.52.54"/><path stroke="#DB836E" d="M81.367 73.084s.48-1.12 1.12-.72 1.28 1.44.56 2 .16 1.68.16 1.68"/><path stroke="#5C2552" d="M92.326 71.724s1.84 1.12 4.16.96"/><path stroke="#DB836E" d="M92.726 80.604s2.24 1.2 4.4 1.2m-3.44 1.36s.96.4 1.52.32m-11.519-3.44s1.786 6.547 9.262 7.954"/><path stroke="#E4EBF7" d="M95.548 91.663s-1.068 2.821-8.298 2.105-10.29-5.044-10.29-5.044"/><path fill="#FFF" d="M78.126 87.478s6.526 4.972 16.47 2.486c0 0 9.577 1.02 11.536 5.322 5.36 11.77.543 36.835 0 39.962 3.496 4.055-.466 8.483-.466 8.483-15.624-3.548-35.81-.6-35.81-.6-4.849-3.546-1.223-9.044-1.223-9.044L62.38 110.32c-2.485-15.227.833-19.803 3.549-20.743 3.03-1.049 8.04-1.282 8.04-1.282.496-.058 1.08-.076 1.37-.233 2.36-1.282 2.787-.583 2.787-.583"/><path fill="#FFC6A0" d="M65.828 89.81s-6.875.465-7.59 8.156c-.466 8.857 3.03 10.954 3.03 10.954s6.075 22.102 16.796 22.957c8.39-2.176 4.758-6.702 4.661-11.42-.233-11.304-7.108-16.897-7.108-16.897s-4.212-13.75-9.789-13.75"/><path fill="#FFC6A0" d="M71.716 124.225s.855 11.264 9.828 6.486c4.765-2.536 7.581-13.828 9.789-22.568 1.456-5.768 2.58-12.197 2.58-12.197l-4.973-1.709s-2.408 5.516-7.769 12.275c-4.335 5.467-9.144 11.11-9.455 17.713"/><path stroke="#E4EBF7" d="M108.463 105.191s1.747 2.724-2.331 30.535c2.376 2.216 1.053 6.012-.233 7.51"/><path fill="#FFC6A0" d="M123.262 131.527s-.427 2.732-11.77 1.981c-15.187-1.006-25.326-3.25-25.326-3.25l.933-5.8s.723.215 9.71-.068c11.887-.373 18.714-6.07 24.964-1.022 4.039 3.263 1.489 8.16 1.489 8.16"/><path fill="#FFF" d="M70.24 90.974s-5.593-4.739-11.054 2.68c-3.318 7.223.517 15.284 2.664 19.578-.31 3.729 2.33 4.311 2.33 4.311s.108.895 1.516 2.68c4.078-7.03 6.72-9.166 13.711-12.546-.328-.656-1.877-3.265-1.825-3.767.175-1.69-1.282-2.623-1.282-2.623s-.286-.156-1.165-2.738c-.788-2.313-2.036-5.177-4.895-7.575"/><path fill="#CBD1D1" d="M90.232 288.027s4.855 2.308 8.313 1.155c3.188-1.063 5.12.755 8.002 1.331 2.881.577 7.769 1.243 13.207-1.424-.117-6.228-7.786-4.499-13.518-7.588-2.895-1.56-4.276-5.336-4.066-9.944H91.544s-1.573 11.89-1.312 16.47"/><path fill="#2B0849" d="M90.207 287.833s2.745 1.437 7.639.738c3.456-.494 3.223.66 7.418 1.282 4.195.621 13.092-.194 14.334-1.126.466 1.242-.388 2.33-.388 2.33s-1.709.682-5.438.932c-2.295.154-8.098.276-10.14-.621-2.02-1.554-4.894-1.515-6.06-.234-4.427 1.075-7.184-.31-7.184-.31z"/><path fill="#A4AABA" d="M98.429 272.257h3.496s-.117 7.574 5.127 9.671c-5.244.7-9.672-2.602-8.623-9.671"/><path fill="#CBD1D1" d="M44.425 272.046s-2.208 7.774-4.702 12.899c-1.884 3.874-4.428 7.854 5.729 7.854 6.97 0 9.385-.503 7.782-6.917-1.604-6.415.279-13.836.279-13.836z"/><path fill="#2B0849" d="M38.066 290.277s2.198 1.225 6.954 1.225c6.376 0 8.646-1.73 8.646-1.73s.63 1.168-.649 2.27c-1.04.897-3.77 1.668-7.745 1.621-4.347-.05-6.115-.593-7.062-1.224-.864-.577-.72-1.657-.144-2.162"/><path fill="#A4AABA" d="M45.344 274.041s.035 1.592-.329 3.07c-.365 1.49-1.13 3.255-1.184 4.34-.061 1.206 4.755 1.657 5.403.036.65-1.622 1.357-6.737 2.006-7.602s-5.14-2.222-5.896.156"/><path fill="#7BB2F9" d="m89.476 277.57 13.899.095s1.349-56.643 1.925-66.909 3.923-45.052 1.042-65.585l-13.037-.669-23.737.81s-.452 4.12-1.243 10.365c-.065.515-.708.874-.777 1.417-.078.608.439 1.407.332 2.044-2.455 14.627-5.797 32.736-8.256 46.837-.121.693-1.282 1.048-1.515 2.796-.042.314.22 1.584.116 1.865-7.14 19.473-12.202 52.601-15.66 67.19l15.176-.015s2.282-10.145 4.185-18.871c2.922-13.389 24.012-88.32 24.012-88.32l3.133-.954-.158 48.568s-.233 1.282.35 2.098-.581 1.167-.408 2.331l.408 1.864s-.466 7.458-.932 12.352c-.467 4.895 1.145 40.69 1.145 40.69"/><path stroke="#648BD8" d="M64.57 218.881c1.197.099 4.195-2.097 7.225-5.127m24.229 8.78s2.881-1.152 6.34-4.034m-5.391.873s2.882-1.153 6.34-4.034m-40.141 6.805s2.724-.614 6.759-3.496m4.972-72.482c-.281 3.226.31 8.856-4.506 9.478m22.785-11.3s.115 14.557-1.344 15.65c-2.305 1.73-3.107 2.02-3.107 2.02m.466-17.091s.269 13.144-1.01 25.088m-4.662.699s6.81-1.051 9.116-1.051M46.026 270.045l-.892 4.538m1.803-11.294-.815 4.157m16.603-64.943c-.33 1.618-.102 1.904-.449 3.438 0 0-2.756 1.903-2.29 3.923s-.31 3.424-4.505 17.252c-1.762 5.807-4.233 18.922-6.165 28.278-.03.144-.521 2.646-1.14 5.8m15.982-67.058c-.295 1.658-.6 3.31-.917 4.938m8.089-52.287-1.244 10.877s-1.14.155-.519 2.33c.117 1.399-2.778 16.39-5.382 31.615m-19.943 82.118H58.07"/><path fill="#192064" d="M106.18 142.117c-3.028-.489-18.825-2.744-36.219.2a.625.625 0 0 0-.518.644c.063 1.307.044 2.343.015 2.995a.617.617 0 0 0 .716.636c3.303-.534 17.037-2.412 35.664-.266.347.04.66-.214.692-.56a41 41 0 0 0 .17-3.029.616.616 0 0 0-.52-.62"/><path fill="#FFF" d="m96.398 145.264.003-5.102a.843.843 0 0 0-.809-.847 114 114 0 0 0-8.141-.014.85.85 0 0 0-.82.847l-.003 5.097c0 .476.388.857.864.845 2.478-.064 5.166-.067 8.03.017a.85.85 0 0 0 .876-.843"/><path fill="#192064" d="m95.239 144.296.002-3.195a.667.667 0 0 0-.643-.672 99 99 0 0 0-6.094-.01.675.675 0 0 0-.654.672l-.002 3.192c0 .376.305.677.68.669 1.859-.042 3.874-.043 6.02.012.376.01.69-.291.691-.668"/><path stroke="#648BD8" d="M90.102 273.522h12.819m-11.705-3.761c.006 3.519-.072 5.55 0 6.292m-.293-12.579c-.009 1.599-.016 2.558-.016 4.505m-.467-97.575.932 46.38s.7 1.631-.233 2.796c-.932 1.166 2.564.7.932 2.33-1.63 1.633.933 1.166 0 3.497-.618 1.546-1.031 21.921-1.138 36.513"/><path stroke="#E4EBF7" d="m73.736 98.665 2.214 4.312s2.098.816 1.865 2.68l.816 2.214m-14.334 8.74c.233-.932 2.176-7.147 12.585-10.488m.716-16.081s7.691 6.137 16.547 2.72"/><path fill="#FFC6A0" d="M91.974 86.954s5.476-.816 7.574-4.545c1.297-.345.72 2.212-.33 3.671-.7.971-1.01 1.554-1.01 1.554s.194.31.155.816c-.053.697-.175.653-.272 1.048-.081.335.108.657 0 1.049-.046.17-.198.5-.382.878-.12.249-.072.687-.2.948-.231.469-1.562 1.87-2.622 2.855-3.826 3.554-5.018 1.644-6.001-.408-.894-1.865-.661-5.127-.874-6.875-.35-2.914-2.622-3.03-1.923-4.429.343-.685 2.87.69 3.263 1.748.757 2.04 2.952 1.807 2.622 1.69"/><path stroke="#DB836E" d="M99.8 82.429c-.465.077-.35.272-.97 1.243-.622.971-4.817 2.932-6.39 3.224-2.589.48-2.278-1.56-4.254-2.855-1.69-1.107-3.562-.638-1.398 1.398.99.932.932 1.107 1.398 3.205.335 1.506-.64 3.67.7 5.593"/><path stroke="#E59788" d="M79.543 108.673c-2.1 2.926-4.266 6.175-5.557 8.762"/><path fill="#FFC6A0" d="M87.72 124.768s-2.098-1.942-5.127-2.719-3.574-.155-5.516.078-3.885-.932-3.652.7c.233 1.63 5.05 1.01 5.206 2.097.155 1.087-6.37 2.796-8.313 2.175-.777.777.466 1.864 2.02 2.175.233 1.554 2.253 1.554 2.253 1.554s.699 1.01 2.641 1.088c2.486 1.32 8.934-.7 10.954-1.554s-.466-5.594-.466-5.594"/><path stroke="#E59788" d="M73.425 122.826s.66 1.127 3.167 1.418c2.315.27 2.563.583 2.563.583s-2.545 2.894-9.07 2.272m2.331 2.175s3.826.097 4.933-.718m-2.369 2.194s1.961.136 3.36-.505m-1.108 1.671s1.748.019 2.914-.505m-6.818-9.09s-.595-1.032 1.262-.427c1.671.544 2.833.055 5.128.155 1.389.061 3.067-.297 3.982.15 1.606.784 3.632 2.181 3.632 2.181s10.526 1.204 19.033-1.127m-27.501-15.149s-8.39 2.758-13.168 12.12"/><path stroke="#E4EBF7" d="M109.278 112.533s3.38-3.613 7.575-4.662"/><path stroke="#E59788" d="M107.375 123.006s9.697-2.745 11.445-.88"/><path stroke="#BFCDDD" d="m194.605 83.656 3.971-3.886m-11.41 11.163 3.736-3.655m.85-3.071-4.462-4.56m11.163 11.41-4.133-4.225m-65.064 76.242 3.718-3.718m-10.683 10.683 3.498-3.498m.772-2.915-4.27-4.27m10.684 10.683-3.955-3.955"/><path fill="#A3B4C6" d="M190.156 211.779h-1.604a4.023 4.023 0 0 1-4.011-4.011V175.68a4.023 4.023 0 0 1 4.01-4.01h1.605a4.023 4.023 0 0 1 4.011 4.01v32.088a4.023 4.023 0 0 1-4.01 4.01"/><path fill="#A3B4C6" d="M237.824 212.977a4.813 4.813 0 0 1-4.813 4.813h-86.636a4.813 4.813 0 0 1 0-9.626h86.636a4.813 4.813 0 0 1 4.813 4.813"/><path fill="#A3B4C6" d="M154.098 190.096h70.513v-84.617h-70.513z" mask="url(#d)"/><path fill="#BFCDDD" d="M224.928 190.096H153.78a3.22 3.22 0 0 1-3.208-3.209V167.92a3.22 3.22 0 0 1 3.208-3.21h71.148a3.22 3.22 0 0 1 3.209 3.21v18.967a3.22 3.22 0 0 1-3.21 3.209m.001-59.264H153.78a3.22 3.22 0 0 1-3.208-3.208v-18.968a3.22 3.22 0 0 1 3.208-3.209h71.148a3.22 3.22 0 0 1 3.209 3.21v18.967a3.22 3.22 0 0 1-3.21 3.208" mask="url(#d)"/><path fill="#FFF" d="M159.563 120.546a2.407 2.407 0 1 1 0-4.813 2.407 2.407 0 0 1 0 4.813m7.417 0a2.407 2.407 0 1 1 0-4.813 2.407 2.407 0 0 1 0 4.813m7.417 0a2.407 2.407 0 1 1 0-4.813 2.407 2.407 0 0 1 0 4.813m48.142 0h-22.461a.8.8 0 0 1-.802-.802v-3.208c0-.443.359-.803.802-.803h22.46c.444 0 .803.36.803.803v3.208c0 .443-.36.802-.802.802" mask="url(#d)"/><path fill="#BFCDDD" d="M224.928 160.464H153.78a3.22 3.22 0 0 1-3.208-3.209v-18.967a3.22 3.22 0 0 1 3.208-3.209h71.148a3.22 3.22 0 0 1 3.209 3.209v18.967a3.22 3.22 0 0 1-3.21 3.209" mask="url(#d)"/><path stroke="#7C90A5" d="M173.455 130.832h49.301m-57.772 0h6.089m-15.121 0h6.75m11.135 29.781h49.3m-57.772 0h6.089m-15.884 0h6.751" mask="url(#d)"/><path fill="#FFF" d="M159.563 151.038a2.407 2.407 0 1 1 0-4.814 2.407 2.407 0 0 1 0 4.814m7.417 0a2.407 2.407 0 1 1 0-4.814 2.407 2.407 0 0 1 0 4.814m7.417 0a2.407 2.407 0 1 1 .001-4.814 2.407 2.407 0 0 1 0 4.814m48.141 0h-22.461a.8.8 0 0 1-.802-.802v-3.209c0-.443.359-.802.802-.802h22.46c.444 0 .803.36.803.802v3.209c0 .443-.36.802-.802.802m-62.976 28.949a2.407 2.407 0 1 1 0-4.813 2.407 2.407 0 0 1 0 4.813m7.417 0a2.407 2.407 0 1 1 0-4.813 2.407 2.407 0 0 1 0 4.813m7.417 0a2.407 2.407 0 1 1 0-4.813 2.407 2.407 0 0 1 0 4.813m48.142 0h-22.461a.8.8 0 0 1-.802-.802v-3.209c0-.443.359-.802.802-.802h22.46c.444 0 .803.36.803.802v3.209c0 .443-.36.802-.802.802" mask="url(#d)"/><path fill="#BFCDDD" d="M203.04 221.108h-27.372a2.413 2.413 0 0 1-2.406-2.407v-11.448a2.414 2.414 0 0 1 2.406-2.407h27.372a2.414 2.414 0 0 1 2.407 2.407V218.7a2.413 2.413 0 0 1-2.407 2.407" mask="url(#d)"/><path stroke="#A3B4C6" d="M177.259 207.217v11.52m23.791-11.52v11.52" mask="url(#d)"/><path fill="#5BA02E" d="M162.873 267.894a9.42 9.42 0 0 1-9.422-9.422v-14.82a9.423 9.423 0 0 1 18.845 0v14.82a9.423 9.423 0 0 1-9.423 9.422" mask="url(#d)"/><path fill="#92C110" d="M171.22 267.83a9.42 9.42 0 0 1-9.422-9.423v-3.438a9.423 9.423 0 0 1 18.845 0v3.438a9.423 9.423 0 0 1-9.422 9.423" mask="url(#d)"/><path fill="#F2D7AD" d="M181.31 293.666h-27.712a3.21 3.21 0 0 1-3.209-3.21V269.79a3.21 3.21 0 0 1 3.209-3.21h27.711a3.21 3.21 0 0 1 3.209 3.21v20.668a3.21 3.21 0 0 1-3.209 3.209" mask="url(#d)"/></g></svg> \ No newline at end of file diff --git a/src/assets/svg/back_top.svg b/src/assets/svg/back_top.svg new file mode 100644 index 0000000..f8e6aa0 --- /dev/null +++ b/src/assets/svg/back_top.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M2.88 18.054a35.9 35.9 0 0 1 8.531-16.32.8.8 0 0 1 1.178 0q.25.27.413.455a35.9 35.9 0 0 1 8.118 15.865c-2.141.451-4.34.747-6.584.874l-2.089 4.178a.5.5 0 0 1-.894 0l-2.089-4.178a44 44 0 0 1-6.584-.874m6.698-1.123 1.157.066L12 19.527l1.265-2.53 1.157-.066a42 42 0 0 0 4.227-.454A33.9 33.9 0 0 0 12 4.09a33.9 33.9 0 0 0-6.649 12.387q2.093.334 4.227.454M12 15a3 3 0 1 1 0-6 3 3 0 0 1 0 6m0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2"/></svg> \ No newline at end of file diff --git a/src/assets/svg/dark.svg b/src/assets/svg/dark.svg new file mode 100644 index 0000000..b5c4d2d --- /dev/null +++ b/src/assets/svg/dark.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.38 2.019a7.5 7.5 0 1 0 10.6 10.6C21.662 17.854 17.316 22 12.001 22 6.477 22 2 17.523 2 12c0-5.315 4.146-9.661 9.38-9.981"/></svg> \ No newline at end of file diff --git a/src/assets/svg/day.svg b/src/assets/svg/day.svg new file mode 100644 index 0000000..b760034 --- /dev/null +++ b/src/assets/svg/day.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12M11 1h2v3h-2zm0 19h2v3h-2zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414zm2.121-14.85 1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414zM23 11v2h-3v-2zM4 11v2H1v-2z"/></svg> \ No newline at end of file diff --git a/src/assets/svg/enter_outlined.svg b/src/assets/svg/enter_outlined.svg new file mode 100644 index 0000000..ab4f9b6 --- /dev/null +++ b/src/assets/svg/enter_outlined.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" class="iconify iconify--ant-design" viewBox="0 0 1024 1024"><path fill="currentColor" d="M864 170h-60c-4.4 0-8 3.6-8 8v518H310v-73c0-6.7-7.8-10.5-13-6.3l-141.9 112a8 8 0 0 0 0 12.6l141.9 112c5.3 4.2 13 .4 13-6.3v-75h498c35.3 0 64-28.7 64-64V178c0-4.4-3.6-8-8-8"/></svg> \ No newline at end of file diff --git a/src/assets/svg/exit_screen.svg b/src/assets/svg/exit_screen.svg new file mode 100644 index 0000000..c431a05 --- /dev/null +++ b/src/assets/svg/exit_screen.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" class="re-screen" color="#00000073" viewBox="0 0 16 16"><path fill="currentColor" d="M3.5 4H1V3h2V1h1v2.5zM13 3V1h-1v2.5l.5.5H15V3zm-1 9.5V15h1v-2h2v-1h-2.5zM1 12v1h2v2h1v-2.5l-.5-.5zm11-1.5-.5.5h-7l-.5-.5v-5l.5-.5h7l.5.5zM10 7H6v2h4z"/></svg> \ No newline at end of file diff --git a/src/assets/svg/full_screen.svg b/src/assets/svg/full_screen.svg new file mode 100644 index 0000000..b7452e4 --- /dev/null +++ b/src/assets/svg/full_screen.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" class="re-screen" color="#00000073" viewBox="0 0 16 16"><path fill="currentColor" d="M3 12h10V4H3zm2-6h6v4H5zM2 6H1V2.5l.5-.5H5v1H2zm13-3.5V6h-1V3h-3V2h3.5zM14 10h1v3.5l-.5.5H11v-1h3zM2 13h3v1H1.5l-.5-.5V10h1z"/></svg> \ No newline at end of file diff --git a/src/assets/svg/keyboard_esc.svg b/src/assets/svg/keyboard_esc.svg new file mode 100644 index 0000000..e128594 --- /dev/null +++ b/src/assets/svg/keyboard_esc.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" class="iconify iconify--mdi" viewBox="0 0 24 24"><path fill="currentColor" d="M1 7h6v2H3v2h4v2H3v2h4v2H1zm10 0h4v2h-4v2h2a2 2 0 0 1 2 2v2c0 1.11-.89 2-2 2H9v-2h4v-2h-2a2 2 0 0 1-2-2V9c0-1.1.9-2 2-2m8 0h2a2 2 0 0 1 2 2v1h-2V9h-2v6h2v-1h2v1c0 1.11-.89 2-2 2h-2a2 2 0 0 1-2-2V9c0-1.1.9-2 2-2"/></svg> \ No newline at end of file diff --git a/src/assets/svg/system.svg b/src/assets/svg/system.svg new file mode 100644 index 0000000..9ad39a5 --- /dev/null +++ b/src/assets/svg/system.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" class="icon" viewBox="0 0 1024 1024"><path d="M554 849.574c0 23.365-18.635 42.307-42 42.307s-42-18.941-42-42.307V662.719c0-23.365 18.635-42.307 42-42.307v-7.051c23.365 0 42 25.993 42 49.358z"/><path d="M893 888.5c0 17.397-14.103 31.5-31.5 31.5h-700c-17.397 0-31.5-14.103-31.5-31.5s14.103-31.5 31.5-31.5h700c17.397 0 31.5 14.103 31.5 31.5m33-714.074C926 135.484 894.686 105 855.744 105H168.256C129.314 105 98 135.484 98 174.426V533h828zM98 630.988C98 669.931 129.314 702 168.256 702h687.488C894.686 702 926 669.931 926 630.988V596H98z"/></svg> \ No newline at end of file diff --git a/src/assets/table-bar/collapse.svg b/src/assets/table-bar/collapse.svg new file mode 100644 index 0000000..0823ae6 --- /dev/null +++ b/src/assets/table-bar/collapse.svg @@ -0,0 +1 @@ +<svg width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M13.79 10.21a1 1 0 0 0 1.42 0 1 1 0 0 0 0-1.42l-2.5-2.5a1 1 0 0 0-.33-.21 1 1 0 0 0-.76 0 1 1 0 0 0-.33.21l-2.5 2.5a1 1 0 0 0 1.42 1.42l.79-.8v5.18l-.79-.8a1 1 0 0 0-1.42 1.42l2.5 2.5a1 1 0 0 0 .33.21.94.94 0 0 0 .76 0 1 1 0 0 0 .33-.21l2.5-2.5a1 1 0 0 0-1.42-1.42l-.79.8V9.41ZM7 4h10a1 1 0 0 0 0-2H7a1 1 0 0 0 0 2m10 16H7a1 1 0 0 0 0 2h10a1 1 0 0 0 0-2"/></svg> \ No newline at end of file diff --git a/src/assets/table-bar/drag.svg b/src/assets/table-bar/drag.svg new file mode 100644 index 0000000..f477f16 --- /dev/null +++ b/src/assets/table-bar/drag.svg @@ -0,0 +1 @@ +<svg width="32" height="32" fill="currentColor" data-icon="holder" viewBox="64 64 896 896"><path d="M300 276.5a56 56 0 1 0 56-97 56 56 0 0 0-56 97m0 284a56 56 0 1 0 56-97 56 56 0 0 0-56 97M640 228a56 56 0 1 0 112 0 56 56 0 0 0-112 0m0 284a56 56 0 1 0 112 0 56 56 0 0 0-112 0M300 844.5a56 56 0 1 0 56-97 56 56 0 0 0-56 97M640 796a56 56 0 1 0 112 0 56 56 0 0 0-112 0"/></svg> \ No newline at end of file diff --git a/src/assets/table-bar/expand.svg b/src/assets/table-bar/expand.svg new file mode 100644 index 0000000..bb41c35 --- /dev/null +++ b/src/assets/table-bar/expand.svg @@ -0,0 +1 @@ +<svg width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M22 4V2H2v2h9v14.17l-5.5-5.5-1.42 1.41L12 22l7.92-7.92-1.42-1.41-5.5 5.5V4z"/></svg> \ No newline at end of file diff --git a/src/assets/table-bar/refresh.svg b/src/assets/table-bar/refresh.svg new file mode 100644 index 0000000..140288c --- /dev/null +++ b/src/assets/table-bar/refresh.svg @@ -0,0 +1 @@ +<svg width="32" height="32" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 11A8.1 8.1 0 0 0 4.5 9M4 5v4h4m-4 4a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4"/></svg> \ No newline at end of file diff --git a/src/assets/table-bar/settings.svg b/src/assets/table-bar/settings.svg new file mode 100644 index 0000000..4ecd077 --- /dev/null +++ b/src/assets/table-bar/settings.svg @@ -0,0 +1 @@ +<svg width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M3.34 17a10 10 0 0 1-.978-2.326 3 3 0 0 0 .002-5.347A10 10 0 0 1 4.865 4.99a3 3 0 0 0 4.631-2.674 10 10 0 0 1 5.007.002 3 3 0 0 0 4.632 2.672A10 10 0 0 1 20.66 7c.433.749.757 1.53.978 2.326a3 3 0 0 0-.002 5.347 10 10 0 0 1-2.501 4.337 3 3 0 0 0-4.631 2.674 10 10 0 0 1-5.007-.002 3 3 0 0 0-4.632-2.672A10 10 0 0 1 3.34 17m5.66.196a5 5 0 0 1 2.25 2.77q.75.071 1.499.001A5 5 0 0 1 15 17.197a5 5 0 0 1 3.525-.565q.435-.614.748-1.298A5 5 0 0 1 18 12c0-1.26.47-2.437 1.273-3.334a8 8 0 0 0-.75-1.298A5 5 0 0 1 15 6.804a5 5 0 0 1-2.25-2.77q-.75-.071-1.499-.001A5 5 0 0 1 9 6.803a5 5 0 0 1-3.525.565 8 8 0 0 0-.748 1.298A5 5 0 0 1 6 12a5 5 0 0 1-1.273 3.334 8 8 0 0 0 .75 1.298A5 5 0 0 1 9 17.196M12 15a3 3 0 1 1 0-6 3 3 0 0 1 0 6m0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2"/></svg> \ No newline at end of file diff --git a/src/assets/user.jpg b/src/assets/user.jpg new file mode 100644 index 0000000..a2973ac --- /dev/null +++ b/src/assets/user.jpg Binary files differ diff --git a/src/components/ReAuth/index.ts b/src/components/ReAuth/index.ts new file mode 100644 index 0000000..975ed2c --- /dev/null +++ b/src/components/ReAuth/index.ts @@ -0,0 +1,5 @@ +import auth from "./src/auth"; + +const Auth = auth; + +export { Auth }; diff --git a/src/components/ReAuth/src/auth.tsx b/src/components/ReAuth/src/auth.tsx new file mode 100644 index 0000000..d2cf9b3 --- /dev/null +++ b/src/components/ReAuth/src/auth.tsx @@ -0,0 +1,20 @@ +import { defineComponent, Fragment } from "vue"; +import { hasAuth } from "@/router/utils"; + +export default defineComponent({ + name: "Auth", + props: { + value: { + type: undefined, + default: [] + } + }, + setup(props, { slots }) { + return () => { + if (!slots) return null; + return hasAuth(props.value) ? ( + <Fragment>{slots.default?.()}</Fragment> + ) : null; + }; + } +}); diff --git a/src/components/ReCol/index.ts b/src/components/ReCol/index.ts new file mode 100644 index 0000000..7a6c937 --- /dev/null +++ b/src/components/ReCol/index.ts @@ -0,0 +1,29 @@ +import { ElCol } from "element-plus"; +import { h, defineComponent } from "vue"; + +// 灏佽element-plus鐨別l-col缁勪欢 +export default defineComponent({ + name: "ReCol", + props: { + value: { + type: Number, + default: 24 + } + }, + render() { + const attrs = this.$attrs; + const val = this.value; + return h( + ElCol, + { + xs: val, + sm: val, + md: val, + lg: val, + xl: val, + ...attrs + }, + { default: () => this.$slots.default() } + ); + } +}); diff --git a/src/components/ReDialog/index.ts b/src/components/ReDialog/index.ts new file mode 100644 index 0000000..b471764 --- /dev/null +++ b/src/components/ReDialog/index.ts @@ -0,0 +1,69 @@ +import { ref } from "vue"; +import reDialog from "./index.vue"; +import { useTimeoutFn } from "@vueuse/core"; +import { withInstall } from "@pureadmin/utils"; +import type { + EventType, + ArgsType, + DialogProps, + ButtonProps, + DialogOptions +} from "./type"; + +const dialogStore = ref<Array<DialogOptions>>([]); + +/** 鎵撳紑寮规 */ +const addDialog = (options: DialogOptions) => { + const open = () => + dialogStore.value.push(Object.assign(options, { visible: true })); + if (options?.openDelay) { + useTimeoutFn(() => { + open(); + }, options.openDelay); + } else { + open(); + } +}; + +/** 鍏抽棴寮规 */ +const closeDialog = (options: DialogOptions, index: number, args?: any) => { + dialogStore.value[index].visible = false; + options.closeCallBack && options.closeCallBack({ options, index, args }); + + const closeDelay = options?.closeDelay ?? 200; + useTimeoutFn(() => { + dialogStore.value.splice(index, 1); + }, closeDelay); +}; + +/** + * @description 鏇存敼寮规鑷韩灞炴�у�� + * @param value 灞炴�у�� + * @param key 灞炴�э紝榛樿`title` + * @param index 寮规绱㈠紩锛堥粯璁0`锛屼唬琛ㄥ彧鏈変竴涓脊妗嗭紝瀵逛簬宓屽寮规瑕佹敼鍝釜寮规鐨勫睘鎬у�煎氨鎶婅寮规绱㈠紩璧嬬粰`index`锛� + */ +const updateDialog = (value: any, key = "title", index = 0) => { + dialogStore.value[index][key] = value; +}; + +/** 鍏抽棴鎵�鏈夊脊妗� */ +const closeAllDialog = () => { + dialogStore.value = []; +}; + +/** 鍗冧竾鍒繕浜嗗湪涓嬮潰杩欎笁澶勫紩鍏ュ苟娉ㄥ唽涓嬶紝鏀惧績娉ㄥ唽锛屼笉浣跨敤`addDialog`璋冪敤灏变笉浼氳鎸傝浇 + * https://github.com/pure-admin/vue-pure-admin/blob/main/src/App.vue#L4 + * https://github.com/pure-admin/vue-pure-admin/blob/main/src/App.vue#L12 + * https://github.com/pure-admin/vue-pure-admin/blob/main/src/App.vue#L22 + */ +const ReDialog = withInstall(reDialog); + +export type { EventType, ArgsType, DialogProps, ButtonProps, DialogOptions }; +export { + ReDialog, + dialogStore, + addDialog, + closeDialog, + updateDialog, + closeAllDialog +}; diff --git a/src/components/ReDialog/index.vue b/src/components/ReDialog/index.vue new file mode 100644 index 0000000..fb3abaf --- /dev/null +++ b/src/components/ReDialog/index.vue @@ -0,0 +1,206 @@ +<script setup lang="ts"> +import { + type EventType, + type ButtonProps, + type DialogOptions, + closeDialog, + dialogStore +} from "./index"; +import { ref, computed } from "vue"; +import { isFunction } from "@pureadmin/utils"; +import Fullscreen from "~icons/ri/fullscreen-fill"; +import ExitFullscreen from "~icons/ri/fullscreen-exit-fill"; + +defineOptions({ + name: "ReDialog" +}); + +const sureBtnMap = ref({}); +const fullscreen = ref(false); + +const footerButtons = computed(() => { + return (options: DialogOptions) => { + return options?.footerButtons?.length > 0 + ? options.footerButtons + : ([ + { + label: "鍙栨秷", + text: true, + bg: true, + btnClick: ({ dialog: { options, index } }) => { + const done = () => + closeDialog(options, index, { command: "cancel" }); + if (options?.beforeCancel && isFunction(options?.beforeCancel)) { + options.beforeCancel(done, { options, index }); + } else { + done(); + } + } + }, + { + label: "纭畾", + type: "primary", + text: true, + bg: true, + popconfirm: options?.popconfirm, + btnClick: ({ dialog: { options, index } }) => { + if (options?.sureBtnLoading) { + sureBtnMap.value[index] = Object.assign( + {}, + sureBtnMap.value[index], + { + loading: true + } + ); + } + const closeLoading = () => { + if (options?.sureBtnLoading) { + sureBtnMap.value[index].loading = false; + } + }; + const done = () => { + closeLoading(); + closeDialog(options, index, { command: "sure" }); + }; + if (options?.beforeSure && isFunction(options?.beforeSure)) { + options.beforeSure(done, { options, index, closeLoading }); + } else { + done(); + } + } + } + ] as Array<ButtonProps>); + }; +}); + +const fullscreenClass = computed(() => { + return [ + "el-icon", + "el-dialog__close", + "-translate-x-2", + "cursor-pointer", + "hover:text-[red]!" + ]; +}); + +function eventsCallBack( + event: EventType, + options: DialogOptions, + index: number, + isClickFullScreen = false +) { + if (!isClickFullScreen) fullscreen.value = options?.fullscreen ?? false; + if (options?.[event] && isFunction(options?.[event])) { + return options?.[event]({ options, index }); + } +} + +function handleClose( + options: DialogOptions, + index: number, + args = { command: "close" } +) { + closeDialog(options, index, args); + eventsCallBack("close", options, index); +} +</script> + +<template> + <el-dialog + v-for="(options, index) in dialogStore" + :key="index" + v-bind="options" + v-model="options.visible" + class="pure-dialog" + :fullscreen="fullscreen ? true : options?.fullscreen ? true : false" + @closed="handleClose(options, index)" + @opened="eventsCallBack('open', options, index)" + @openAutoFocus="eventsCallBack('openAutoFocus', options, index)" + @closeAutoFocus="eventsCallBack('closeAutoFocus', options, index)" + > + <!-- header --> + <template + v-if="options?.fullscreenIcon || options?.headerRenderer" + #header="{ close, titleId, titleClass }" + > + <div + v-if="options?.fullscreenIcon" + class="flex items-center justify-between" + > + <span :id="titleId" :class="titleClass">{{ options?.title }}</span> + <i + v-if="!options?.fullscreen" + :class="fullscreenClass" + @click=" + () => { + fullscreen = !fullscreen; + eventsCallBack( + 'fullscreenCallBack', + { ...options, fullscreen }, + index, + true + ); + } + " + > + <IconifyIconOffline + class="pure-dialog-svg" + :icon=" + options?.fullscreen + ? ExitFullscreen + : fullscreen + ? ExitFullscreen + : Fullscreen + " + /> + </i> + </div> + <component + :is="options?.headerRenderer({ close, titleId, titleClass })" + v-else + /> + </template> + <component + v-bind="options?.props" + :is="options.contentRenderer({ options, index })" + @close="args => handleClose(options, index, args)" + /> + <!-- footer --> + <template v-if="!options?.hideFooter" #footer> + <template v-if="options?.footerRenderer"> + <component :is="options?.footerRenderer({ options, index })" /> + </template> + <span v-else> + <template v-for="(btn, key) in footerButtons(options)" :key="key"> + <el-popconfirm + v-if="btn.popconfirm" + v-bind="btn.popconfirm" + @confirm=" + btn.btnClick({ + dialog: { options, index }, + button: { btn, index: key } + }) + " + > + <template #reference> + <el-button v-bind="btn">{{ btn?.label }}</el-button> + </template> + </el-popconfirm> + <el-button + v-else + v-bind="btn" + :loading="key === 1 && sureBtnMap[index]?.loading" + @click=" + btn.btnClick({ + dialog: { options, index }, + button: { btn, index: key } + }) + " + > + {{ btn?.label }} + </el-button> + </template> + </span> + </template> + </el-dialog> +</template> diff --git a/src/components/ReDialog/type.ts b/src/components/ReDialog/type.ts new file mode 100644 index 0000000..7efbe20 --- /dev/null +++ b/src/components/ReDialog/type.ts @@ -0,0 +1,275 @@ +import type { CSSProperties, VNode, Component } from "vue"; + +type DoneFn = (cancel?: boolean) => void; +type EventType = + | "open" + | "close" + | "openAutoFocus" + | "closeAutoFocus" + | "fullscreenCallBack"; +type ArgsType = { + /** `cancel` 鐐瑰嚮鍙栨秷鎸夐挳銆乣sure` 鐐瑰嚮纭畾鎸夐挳銆乣close` 鐐瑰嚮鍙充笂瑙掑叧闂寜閽垨绌虹櫧椤垫垨鎸変笅浜唀sc閿� */ + command: "cancel" | "sure" | "close"; +}; +type ButtonType = + | "primary" + | "success" + | "warning" + | "danger" + | "info" + | "text"; + +/** https://element-plus.org/zh-CN/component/dialog.html#attributes */ +type DialogProps = { + /** `Dialog` 鐨勬樉绀轰笌闅愯棌 */ + visible?: boolean; + /** `Dialog` 鐨勬爣棰� */ + title?: string; + /** `Dialog` 鐨勫搴︼紝榛樿 `50%` */ + width?: string | number; + /** 鏄惁涓哄叏灞� `Dialog`锛堜細涓�鐩村浜庡叏灞忕姸鎬侊紝闄ら潪寮规鍏抽棴锛夛紝榛樿 `false`锛宍fullscreen` 鍜� `fullscreenIcon` 閮戒紶鏃跺彧鏈� `fullscreen` 浼氱敓鏁� */ + fullscreen?: boolean; + /** 鏄惁鏄剧ず鍏ㄥ睆鎿嶄綔鍥炬爣锛岄粯璁� `false`锛宍fullscreen` 鍜� `fullscreenIcon` 閮戒紶鏃跺彧鏈� `fullscreen` 浼氱敓鏁� */ + fullscreenIcon?: boolean; + /** `Dialog CSS` 涓殑 `margin-top` 鍊硷紝榛樿 `15vh` */ + top?: string; + /** 鏄惁闇�瑕侀伄缃╁眰锛岄粯璁� `true` */ + modal?: boolean; + /** `Dialog` 鑷韩鏄惁鎻掑叆鑷� `body` 鍏冪礌涓娿�傚祵濂楃殑 `Dialog` 蹇呴』鎸囧畾璇ュ睘鎬у苟璧嬪�间负 `true`锛岄粯璁� `false` */ + appendToBody?: boolean; + /** 鏄惁鍦� `Dialog` 鍑虹幇鏃跺皢 `body` 婊氬姩閿佸畾锛岄粯璁� `true` */ + lockScroll?: boolean; + /** `Dialog` 鐨勮嚜瀹氫箟绫诲悕 */ + class?: string; + /** `Dialog` 鐨勮嚜瀹氫箟鏍峰紡 */ + style?: CSSProperties; + /** `Dialog` 鎵撳紑鐨勫欢鏃舵椂闂达紝鍗曚綅姣锛岄粯璁� `0` */ + openDelay?: number; + /** `Dialog` 鍏抽棴鐨勫欢鏃舵椂闂达紝鍗曚綅姣锛岄粯璁� `0` */ + closeDelay?: number; + /** 鏄惁鍙互閫氳繃鐐瑰嚮 `modal` 鍏抽棴 `Dialog`锛岄粯璁� `true` */ + closeOnClickModal?: boolean; + /** 鏄惁鍙互閫氳繃鎸変笅 `ESC` 鍏抽棴 `Dialog`锛岄粯璁� `true` */ + closeOnPressEscape?: boolean; + /** 鏄惁鏄剧ず鍏抽棴鎸夐挳锛岄粯璁� `true` */ + showClose?: boolean; + /** 鍏抽棴鍓嶇殑鍥炶皟锛屼細鏆傚仠 `Dialog` 鐨勫叧闂�. 鍥炶皟鍑芥暟鍐呮墽琛� `done` 鍙傛暟鏂规硶鐨勬椂鍊欐墠鏄湡姝e叧闂璇濇鐨勬椂鍊� */ + beforeClose?: (done: DoneFn) => void; + /** 涓� `Dialog` 鍚敤鍙嫋鎷藉姛鑳斤紝榛樿 `false` */ + draggable?: boolean; + /** 鏄惁璁� `Dialog` 鐨� `header` 鍜� `footer` 閮ㄥ垎灞呬腑鎺掑垪锛岄粯璁� `false` */ + center?: boolean; + /** 鏄惁姘村钩鍨傜洿瀵归綈瀵硅瘽妗嗭紝榛樿 `false` */ + alignCenter?: boolean; + /** 褰撳叧闂� `Dialog` 鏃讹紝閿�姣佸叾涓殑鍏冪礌锛岄粯璁� `false` */ + destroyOnClose?: boolean; +}; + +//element-plus.org/zh-CN/component/popconfirm.html#attributes +type Popconfirm = { + /** 鏍囬 */ + title?: string; + /** 纭畾鎸夐挳鏂囧瓧 */ + confirmButtonText?: string; + /** 鍙栨秷鎸夐挳鏂囧瓧 */ + cancelButtonText?: string; + /** 纭畾鎸夐挳绫诲瀷锛岄粯璁� `primary` */ + confirmButtonType?: ButtonType; + /** 鍙栨秷鎸夐挳绫诲瀷锛岄粯璁� `text` */ + cancelButtonType?: ButtonType; + /** 鑷畾涔夊浘鏍囷紝榛樿 `QuestionFilled` */ + icon?: string | Component; + /** `Icon` 棰滆壊锛岄粯璁� `#f90` */ + iconColor?: string; + /** 鏄惁闅愯棌 `Icon`锛岄粯璁� `false` */ + hideIcon?: boolean; + /** 鍏抽棴鏃剁殑寤惰繜锛岄粯璁� `200` */ + hideAfter?: number; + /** 鏄惁灏� `popover` 鐨勪笅鎷夊垪琛ㄦ彃鍏ヨ嚦 `body` 鍏冪礌锛岄粯璁� `true` */ + teleported?: boolean; + /** 褰� `popover` 缁勪欢闀挎椂闂翠笉瑙﹀彂涓� `persistent` 灞炴�ц缃负 `false` 鏃�, `popover` 灏嗕細琚垹闄わ紝榛樿 `false` */ + persistent?: boolean; + /** 寮瑰眰瀹藉害锛屾渶灏忓搴� `150px`锛岄粯璁� `150` */ + width?: string | number; +}; + +type BtnClickDialog = { + options?: DialogOptions; + index?: number; +}; +type BtnClickButton = { + btn?: ButtonProps; + index?: number; +}; +/** https://element-plus.org/zh-CN/component/button.html#button-attributes */ +type ButtonProps = { + /** 鎸夐挳鏂囧瓧 */ + label: string; + /** 鎸夐挳灏哄 */ + size?: "large" | "default" | "small"; + /** 鎸夐挳绫诲瀷 */ + type?: "primary" | "success" | "warning" | "danger" | "info"; + /** 鏄惁涓烘湸绱犳寜閽紝榛樿 `false` */ + plain?: boolean; + /** 鏄惁涓烘枃瀛楁寜閽紝榛樿 `false` */ + text?: boolean; + /** 鏄惁鏄剧ず鏂囧瓧鎸夐挳鑳屾櫙棰滆壊锛岄粯璁� `false` */ + bg?: boolean; + /** 鏄惁涓洪摼鎺ユ寜閽紝榛樿 `false` */ + link?: boolean; + /** 鏄惁涓哄渾瑙掓寜閽紝榛樿 `false` */ + round?: boolean; + /** 鏄惁涓哄渾褰㈡寜閽紝榛樿 `false` */ + circle?: boolean; + /** 纭畾鎸夐挳鐨� `Popconfirm` 姘旀场纭妗嗙浉鍏抽厤缃� */ + popconfirm?: Popconfirm; + /** 鏄惁涓哄姞杞戒腑鐘舵�侊紝榛樿 `false` */ + loading?: boolean; + /** 鑷畾涔夊姞杞戒腑鐘舵�佸浘鏍囩粍浠� */ + loadingIcon?: string | Component; + /** 鎸夐挳鏄惁涓虹鐢ㄧ姸鎬侊紝榛樿 `false` */ + disabled?: boolean; + /** 鍥炬爣缁勪欢 */ + icon?: string | Component; + /** 鏄惁寮�鍚師鐢� `autofocus` 灞炴�э紝榛樿 `false` */ + autofocus?: boolean; + /** 鍘熺敓 `type` 灞炴�э紝榛樿 `button` */ + nativeType?: "button" | "submit" | "reset"; + /** 鑷姩鍦ㄤ袱涓腑鏂囧瓧绗︿箣闂存彃鍏ョ┖鏍� */ + autoInsertSpace?: boolean; + /** 鑷畾涔夋寜閽鑹�, 骞惰嚜鍔ㄨ绠� `hover` 鍜� `active` 瑙﹀彂鍚庣殑棰滆壊 */ + color?: string; + /** `dark` 妯″紡, 鎰忓懗鐫�鑷姩璁剧疆 `color` 涓� `dark` 妯″紡鐨勯鑹诧紝榛樿 `false` */ + dark?: boolean; + /** 鑷畾涔夊厓绱犳爣绛� */ + tag?: string | Component; + /** 鐐瑰嚮鎸夐挳鍚庤Е鍙戠殑鍥炶皟 */ + btnClick?: ({ + dialog, + button + }: { + /** 褰撳墠 `Dialog` 淇℃伅 */ + dialog: BtnClickDialog; + /** 褰撳墠 `button` 淇℃伅 */ + button: BtnClickButton; + }) => void; +}; + +interface DialogOptions extends DialogProps { + /** 鍐呭鍖虹粍浠剁殑 `props`锛屽彲閫氳繃 `defineProps` 鎺ユ敹 */ + props?: any; + /** 鏄惁闅愯棌 `Dialog` 鎸夐挳鎿嶄綔鍖虹殑鍐呭 */ + hideFooter?: boolean; + /** 纭畾鎸夐挳鐨� `Popconfirm` 姘旀场纭妗嗙浉鍏抽厤缃� */ + popconfirm?: Popconfirm; + /** 鐐瑰嚮纭畾鎸夐挳鍚庢槸鍚﹀紑鍚� `loading` 鍔犺浇鍔ㄧ敾 */ + sureBtnLoading?: boolean; + /** + * @description 鑷畾涔夊璇濇鏍囬鐨勫唴瀹规覆鏌撳櫒 + * @see {@link https://element-plus.org/zh-CN/component/dialog.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E5%A4%B4%E9%83%A8} + */ + headerRenderer?: ({ + close, + titleId, + titleClass + }: { + close: Function; + titleId: string; + titleClass: string; + }) => VNode | Component; + /** 鑷畾涔夊唴瀹规覆鏌撳櫒 */ + contentRenderer?: ({ + options, + index + }: { + options: DialogOptions; + index: number; + }) => VNode | Component; + /** 鑷畾涔夋寜閽搷浣滃尯鐨勫唴瀹规覆鏌撳櫒锛屼細瑕嗙洊`footerButtons`浠ュ強榛樿鐨� `鍙栨秷` 鍜� `纭畾` 鎸夐挳 */ + footerRenderer?: ({ + options, + index + }: { + options: DialogOptions; + index: number; + }) => VNode | Component; + /** 鑷畾涔夊簳閮ㄦ寜閽搷浣� */ + footerButtons?: Array<ButtonProps>; + /** `Dialog` 鎵撳紑鍚庣殑鍥炶皟 */ + open?: ({ + options, + index + }: { + options: DialogOptions; + index: number; + }) => void; + /** `Dialog` 鍏抽棴鍚庣殑鍥炶皟锛堝彧鏈夌偣鍑诲彸涓婅鍏抽棴鎸夐挳鎴栫┖鐧介〉鎴栨寜涓嬩簡esc閿叧闂〉闈㈡椂鎵嶄細瑙﹀彂锛� */ + close?: ({ + options, + index + }: { + options: DialogOptions; + index: number; + }) => void; + /** `Dialog` 鍏抽棴鍚庣殑鍥炶皟銆� `args` 杩斿洖鐨� `command` 鍊艰В鏋愶細`cancel` 鐐瑰嚮鍙栨秷鎸夐挳銆乣sure` 鐐瑰嚮纭畾鎸夐挳銆乣close` 鐐瑰嚮鍙充笂瑙掑叧闂寜閽垨绌虹櫧椤垫垨鎸変笅浜唀sc閿� */ + closeCallBack?: ({ + options, + index, + args + }: { + options: DialogOptions; + index: number; + args: any; + }) => void; + /** 鐐瑰嚮鍏ㄥ睆鎸夐挳鏃剁殑鍥炶皟 */ + fullscreenCallBack?: ({ + options, + index + }: { + options: DialogOptions; + index: number; + }) => void; + /** 杈撳叆鐒︾偣鑱氱劍鍦� `Dialog` 鍐呭鏃剁殑鍥炶皟 */ + openAutoFocus?: ({ + options, + index + }: { + options: DialogOptions; + index: number; + }) => void; + /** 杈撳叆鐒︾偣浠� `Dialog` 鍐呭澶辩劍鏃剁殑鍥炶皟 */ + closeAutoFocus?: ({ + options, + index + }: { + options: DialogOptions; + index: number; + }) => void; + /** 鐐瑰嚮搴曢儴鍙栨秷鎸夐挳鐨勫洖璋冿紝浼氭殏鍋� `Dialog` 鐨勫叧闂�. 鍥炶皟鍑芥暟鍐呮墽琛� `done` 鍙傛暟鏂规硶鐨勬椂鍊欐墠鏄湡姝e叧闂璇濇鐨勬椂鍊� */ + beforeCancel?: ( + done: Function, + { + options, + index + }: { + options: DialogOptions; + index: number; + } + ) => void; + /** 鐐瑰嚮搴曢儴纭畾鎸夐挳鐨勫洖璋冿紝浼氭殏鍋� `Dialog` 鐨勫叧闂�. 鍥炶皟鍑芥暟鍐呮墽琛� `done` 鍙傛暟鏂规硶鐨勬椂鍊欐墠鏄湡姝e叧闂璇濇鐨勬椂鍊� */ + beforeSure?: ( + done: Function, + { + options, + index, + closeLoading + }: { + options: DialogOptions; + index: number; + /** 鍏抽棴纭畾鎸夐挳鐨� `loading` 鍔犺浇鍔ㄧ敾 */ + closeLoading: Function; + } + ) => void; +} + +export type { EventType, ArgsType, DialogProps, ButtonProps, DialogOptions }; diff --git a/src/components/ReIcon/index.ts b/src/components/ReIcon/index.ts new file mode 100644 index 0000000..86efe72 --- /dev/null +++ b/src/components/ReIcon/index.ts @@ -0,0 +1,12 @@ +import iconifyIconOffline from "./src/iconifyIconOffline"; +import iconifyIconOnline from "./src/iconifyIconOnline"; +import fontIcon from "./src/iconfont"; + +/** 鏈湴鍥炬爣缁勪欢 */ +const IconifyIconOffline = iconifyIconOffline; +/** 鍦ㄧ嚎鍥炬爣缁勪欢 */ +const IconifyIconOnline = iconifyIconOnline; +/** `iconfont`缁勪欢 */ +const FontIcon = fontIcon; + +export { IconifyIconOffline, IconifyIconOnline, FontIcon }; diff --git a/src/components/ReIcon/src/hooks.ts b/src/components/ReIcon/src/hooks.ts new file mode 100644 index 0000000..57ef18d --- /dev/null +++ b/src/components/ReIcon/src/hooks.ts @@ -0,0 +1,63 @@ +import type { iconType } from "./types"; +import { h, defineComponent, type Component } from "vue"; +import { FontIcon, IconifyIconOnline, IconifyIconOffline } from "../index"; + +/** + * 鏀寔 `iconfont`銆佽嚜瀹氫箟 `svg` 浠ュ強 `iconify` 涓墍鏈夌殑鍥炬爣 + * @see 鐐瑰嚮鏌ョ湅鏂囨。鍥炬爣绡� {@link https://pure-admin.cn/pages/icon/} + * @param icon 蹇呬紶 鍥炬爣 + * @param attrs 鍙�� iconType 灞炴�� + * @returns Component + */ +export function useRenderIcon(icon: any, attrs?: iconType): Component { + // iconfont + const ifReg = /^IF-/; + // typeof icon === "function" 灞炰簬SVG + if (ifReg.test(icon)) { + // iconfont + const name = icon.split(ifReg)[1]; + const iconName = name.slice( + 0, + name.indexOf(" ") == -1 ? name.length : name.indexOf(" ") + ); + const iconType = name.slice(name.indexOf(" ") + 1, name.length); + return defineComponent({ + name: "FontIcon", + render() { + return h(FontIcon, { + icon: iconName, + iconType, + ...attrs + }); + } + }); + } else if (typeof icon === "function" || typeof icon?.render === "function") { + // svg + return attrs ? h(icon, { ...attrs }) : icon; + } else if (typeof icon === "object") { + return defineComponent({ + name: "OfflineIcon", + render() { + return h(IconifyIconOffline, { + icon: icon, + ...attrs + }); + } + }); + } else { + // 閫氳繃鏄惁瀛樺湪 : 绗﹀彿鏉ュ垽鏂槸鍦ㄧ嚎杩樻槸鏈湴鍥炬爣锛屽瓨鍦ㄥ嵆鏄湪绾垮浘鏍囷紝鍙嶄箣 + return defineComponent({ + name: "Icon", + render() { + if (!icon) return; + const IconifyIcon = icon.includes(":") + ? IconifyIconOnline + : IconifyIconOffline; + return h(IconifyIcon, { + icon, + ...attrs + }); + } + }); + } +} diff --git a/src/components/ReIcon/src/iconfont.ts b/src/components/ReIcon/src/iconfont.ts new file mode 100644 index 0000000..df60f25 --- /dev/null +++ b/src/components/ReIcon/src/iconfont.ts @@ -0,0 +1,47 @@ +import { h, defineComponent } from "vue"; + +// 灏佽iconfont缁勪欢锛岄粯璁font-class`寮曠敤妯″紡锛屾敮鎸乣unicode`寮曠敤銆乣font-class`寮曠敤銆乣symbol`寮曠敤 锛坔ttps://www.iconfont.cn/help/detail?spm=a313x.7781069.1998910419.20&helptype=code锛� +export default defineComponent({ + name: "FontIcon", + props: { + icon: { + type: String, + default: "" + } + }, + render() { + const attrs = this.$attrs; + if (Object.keys(attrs).includes("uni") || attrs?.iconType === "uni") { + return h( + "i", + { + class: "iconfont", + ...attrs + }, + this.icon + ); + } else if ( + Object.keys(attrs).includes("svg") || + attrs?.iconType === "svg" + ) { + return h( + "svg", + { + class: "icon-svg" + }, + { + default: () => [ + h("use", { + "xlink:href": `#${this.icon}` + }) + ] + } + ); + } else { + return h("i", { + class: `iconfont ${this.icon}`, + ...attrs + }); + } + } +}); diff --git a/src/components/ReIcon/src/iconifyIconOffline.ts b/src/components/ReIcon/src/iconifyIconOffline.ts new file mode 100644 index 0000000..e5782b2 --- /dev/null +++ b/src/components/ReIcon/src/iconifyIconOffline.ts @@ -0,0 +1,47 @@ +import { h, defineComponent } from "vue"; +import { Icon as IconifyIcon, addIcon } from "@iconify/vue/dist/offline"; + +// Iconify Icon鍦╒ue閲屾湰鍦颁娇鐢紙鐢ㄤ簬鍐呯綉鐜锛� +export default defineComponent({ + name: "IconifyIconOffline", + components: { IconifyIcon }, + props: { + icon: { + default: null + } + }, + render() { + if (typeof this.icon === "object") addIcon(this.icon, this.icon); + const attrs = this.$attrs; + if (typeof this.icon === "string") { + return h( + IconifyIcon, + { + icon: this.icon, + "aria-hidden": false, + style: attrs?.style + ? Object.assign(attrs.style, { outline: "none" }) + : { outline: "none" }, + ...attrs + }, + { + default: () => [] + } + ); + } else { + return h( + this.icon, + { + "aria-hidden": false, + style: attrs?.style + ? Object.assign(attrs.style, { outline: "none" }) + : { outline: "none" }, + ...attrs + }, + { + default: () => [] + } + ); + } + } +}); diff --git a/src/components/ReIcon/src/iconifyIconOnline.ts b/src/components/ReIcon/src/iconifyIconOnline.ts new file mode 100644 index 0000000..8467e07 --- /dev/null +++ b/src/components/ReIcon/src/iconifyIconOnline.ts @@ -0,0 +1,31 @@ +import { h, defineComponent } from "vue"; +import { Icon as IconifyIcon } from "@iconify/vue"; + +// Iconify Icon鍦╒ue閲屽湪绾夸娇鐢紙鐢ㄤ簬澶栫綉鐜锛� +export default defineComponent({ + name: "IconifyIconOnline", + components: { IconifyIcon }, + props: { + icon: { + type: String, + default: "" + } + }, + render() { + const attrs = this.$attrs; + return h( + IconifyIcon, + { + icon: `${this.icon}`, + "aria-hidden": false, + style: attrs?.style + ? Object.assign(attrs.style, { outline: "none" }) + : { outline: "none" }, + ...attrs + }, + { + default: () => [] + } + ); + } +}); diff --git a/src/components/ReIcon/src/offlineIcon.ts b/src/components/ReIcon/src/offlineIcon.ts new file mode 100644 index 0000000..b820740 --- /dev/null +++ b/src/components/ReIcon/src/offlineIcon.ts @@ -0,0 +1,23 @@ +// 杩欓噷瀛樻斁鏈湴鍥炬爣锛屽湪 src/layout/index.vue 鏂囦欢涓姞杞斤紝閬垮厤鍦ㄩ鍚姩鍔犺浇 +import { getSvgInfo } from "@pureadmin/utils"; +import { addIcon } from "@iconify/vue/dist/offline"; + +// https://icon-sets.iconify.design/ep/?keyword=ep +import EpHomeFilled from "~icons/ep/home-filled?raw"; + +// https://icon-sets.iconify.design/ri/?keyword=ri +import RiSearchLine from "~icons/ri/search-line?raw"; +import RiInformationLine from "~icons/ri/information-line?raw"; + +const icons = [ + // Element Plus Icon: https://github.com/element-plus/element-plus-icons + ["ep/home-filled", EpHomeFilled], + // Remix Icon: https://github.com/Remix-Design/RemixIcon + ["ri/search-line", RiSearchLine], + ["ri/information-line", RiInformationLine] +]; + +// 鏈湴鑿滃崟鍥炬爣锛屽悗绔湪璺敱鐨� icon 涓繑鍥炲搴旂殑鍥炬爣瀛楃涓插苟涓斿墠绔湪姝ゅ浣跨敤 addIcon 娣诲姞鍗冲彲娓叉煋鑿滃崟鍥炬爣 +icons.forEach(([name, icon]) => { + addIcon(name as string, getSvgInfo(icon as string)); +}); diff --git a/src/components/ReIcon/src/types.ts b/src/components/ReIcon/src/types.ts new file mode 100644 index 0000000..000bdc5 --- /dev/null +++ b/src/components/ReIcon/src/types.ts @@ -0,0 +1,20 @@ +export interface iconType { + // iconify (https://docs.iconify.design/icon-components/vue/#properties) + inline?: boolean; + width?: string | number; + height?: string | number; + horizontalFlip?: boolean; + verticalFlip?: boolean; + flip?: string; + rotate?: number | string; + color?: string; + horizontalAlign?: boolean; + verticalAlign?: boolean; + align?: string; + onLoad?: Function; + includes?: Function; + // svg 闇�瑕佷粈涔圫VG灞炴�ц嚜琛屾坊鍔� + fill?: string; + // all icon + style?: object; +} diff --git a/src/components/RePerms/index.ts b/src/components/RePerms/index.ts new file mode 100644 index 0000000..3701c3c --- /dev/null +++ b/src/components/RePerms/index.ts @@ -0,0 +1,5 @@ +import perms from "./src/perms"; + +const Perms = perms; + +export { Perms }; diff --git a/src/components/RePerms/src/perms.tsx b/src/components/RePerms/src/perms.tsx new file mode 100644 index 0000000..da01bc1 --- /dev/null +++ b/src/components/RePerms/src/perms.tsx @@ -0,0 +1,20 @@ +import { defineComponent, Fragment } from "vue"; +import { hasPerms } from "@/utils/auth"; + +export default defineComponent({ + name: "Perms", + props: { + value: { + type: undefined, + default: [] + } + }, + setup(props, { slots }) { + return () => { + if (!slots) return null; + return hasPerms(props.value) ? ( + <Fragment>{slots.default?.()}</Fragment> + ) : null; + }; + } +}); diff --git a/src/components/RePureTableBar/index.ts b/src/components/RePureTableBar/index.ts new file mode 100644 index 0000000..31b8a16 --- /dev/null +++ b/src/components/RePureTableBar/index.ts @@ -0,0 +1,5 @@ +import pureTableBar from "./src/bar"; +import { withInstall } from "@pureadmin/utils"; + +/** 閰嶅悎 `@pureadmin/table` 瀹炵幇蹇�熶究鎹风殑琛ㄦ牸鎿嶄綔 https://github.com/pure-admin/pure-admin-table */ +export const PureTableBar = withInstall(pureTableBar); diff --git a/src/components/RePureTableBar/src/bar.tsx b/src/components/RePureTableBar/src/bar.tsx new file mode 100644 index 0000000..1dfadbe --- /dev/null +++ b/src/components/RePureTableBar/src/bar.tsx @@ -0,0 +1,393 @@ +import Sortable from "sortablejs"; +import { useEpThemeStoreHook } from "@/store/modules/epTheme"; +import { + type PropType, + ref, + unref, + computed, + nextTick, + defineComponent, + getCurrentInstance +} from "vue"; +import { + delay, + cloneDeep, + isBoolean, + isFunction, + getKeyList +} from "@pureadmin/utils"; + +import Fullscreen from "~icons/ri/fullscreen-fill"; +import ExitFullscreen from "~icons/ri/fullscreen-exit-fill"; +import DragIcon from "@/assets/table-bar/drag.svg?component"; +import ExpandIcon from "@/assets/table-bar/expand.svg?component"; +import RefreshIcon from "@/assets/table-bar/refresh.svg?component"; +import SettingIcon from "@/assets/table-bar/settings.svg?component"; +import CollapseIcon from "@/assets/table-bar/collapse.svg?component"; + +const props = { + /** 澶撮儴鏈�宸﹁竟鐨勬爣棰� */ + title: { + type: String, + default: "鍒楄〃" + }, + /** 瀵逛簬鏍戝舰琛ㄦ牸锛屽鏋滄兂鍚敤灞曞紑鍜屾姌鍙犲姛鑳斤紝浼犲叆褰撳墠琛ㄦ牸鐨剅ef鍗冲彲 */ + tableRef: { + type: Object as PropType<any> + }, + /** 闇�瑕佸睍绀虹殑鍒� */ + columns: { + type: Array as PropType<TableColumnList>, + default: () => [] + }, + isExpandAll: { + type: Boolean, + default: true + }, + tableKey: { + type: [String, Number] as PropType<string | number>, + default: "0" + } +}; + +export default defineComponent({ + name: "PureTableBar", + props, + emits: ["refresh", "fullscreen"], + setup(props, { emit, slots, attrs }) { + const size = ref("default"); + const loading = ref(false); + const checkAll = ref(true); + const isFullscreen = ref(false); + const isIndeterminate = ref(false); + const instance = getCurrentInstance()!; + const isExpandAll = ref(props.isExpandAll); + const filterColumns = cloneDeep(props?.columns).filter(column => + isBoolean(column?.hide) + ? !column.hide + : !(isFunction(column?.hide) && column?.hide()) + ); + let checkColumnList = getKeyList(cloneDeep(props?.columns), "label"); + const checkedColumns = ref(getKeyList(cloneDeep(filterColumns), "label")); + const dynamicColumns = ref(cloneDeep(props?.columns)); + + const getDropdownItemStyle = computed(() => { + return s => { + return { + background: + s === size.value ? useEpThemeStoreHook().epThemeColor : "", + color: s === size.value ? "#fff" : "var(--el-text-color-primary)" + }; + }; + }); + + const iconClass = computed(() => { + return [ + "text-black", + "dark:text-white", + "duration-100", + "hover:text-primary!", + "cursor-pointer", + "outline-hidden" + ]; + }); + + const topClass = computed(() => { + return [ + "flex", + "justify-between", + "pt-[3px]", + "px-[11px]", + "border-b-[1px]", + "border-solid", + "border-[#dcdfe6]", + "dark:border-[#303030]" + ]; + }); + + function onReFresh() { + loading.value = true; + emit("refresh"); + delay(500).then(() => (loading.value = false)); + } + + function onExpand() { + isExpandAll.value = !isExpandAll.value; + toggleRowExpansionAll(props.tableRef.data, isExpandAll.value); + } + + function onFullscreen() { + isFullscreen.value = !isFullscreen.value; + emit("fullscreen", isFullscreen.value); + } + + function toggleRowExpansionAll(data, isExpansion) { + data.forEach(item => { + props.tableRef.toggleRowExpansion(item, isExpansion); + if (item.children !== undefined && item.children !== null) { + toggleRowExpansionAll(item.children, isExpansion); + } + }); + } + + function handleCheckAllChange(val: boolean) { + checkedColumns.value = val ? checkColumnList : []; + isIndeterminate.value = false; + dynamicColumns.value.map(column => + val ? (column.hide = false) : (column.hide = true) + ); + } + + function handleCheckedColumnsChange(value: string[]) { + checkedColumns.value = value; + const checkedCount = value.length; + checkAll.value = checkedCount === checkColumnList.length; + isIndeterminate.value = + checkedCount > 0 && checkedCount < checkColumnList.length; + } + + function handleCheckColumnListChange(val: boolean, label: string) { + dynamicColumns.value.filter(item => item.label === label)[0].hide = !val; + } + + async function onReset() { + checkAll.value = true; + isIndeterminate.value = false; + dynamicColumns.value = cloneDeep(props?.columns); + checkColumnList = []; + checkColumnList = await getKeyList(cloneDeep(props?.columns), "label"); + checkedColumns.value = getKeyList(cloneDeep(filterColumns), "label"); + } + + const dropdown = { + dropdown: () => ( + <el-dropdown-menu class="translation"> + <el-dropdown-item + style={getDropdownItemStyle.value("large")} + onClick={() => (size.value = "large")} + > + 瀹芥澗 + </el-dropdown-item> + <el-dropdown-item + style={getDropdownItemStyle.value("default")} + onClick={() => (size.value = "default")} + > + 榛樿 + </el-dropdown-item> + <el-dropdown-item + style={getDropdownItemStyle.value("small")} + onClick={() => (size.value = "small")} + > + 绱у噾 + </el-dropdown-item> + </el-dropdown-menu> + ) + }; + + /** 鍒楀睍绀烘嫋鎷芥帓搴� */ + const rowDrop = (event: { preventDefault: () => void }) => { + event.preventDefault(); + nextTick(() => { + const wrapper: HTMLElement = ( + instance?.proxy?.$refs[`GroupRef${unref(props.tableKey)}`] as any + ).$el.firstElementChild; + Sortable.create(wrapper, { + animation: 300, + handle: ".drag-btn", + onEnd: ({ newIndex, oldIndex, item }) => { + const targetThElem = item; + const wrapperElem = targetThElem.parentNode as HTMLElement; + const oldColumn = dynamicColumns.value[oldIndex]; + const newColumn = dynamicColumns.value[newIndex]; + if (oldColumn?.fixed || newColumn?.fixed) { + // 褰撳墠鍒楀瓨鍦╢ixed灞炴�� 鍒欎笉鍙嫋鎷� + const oldThElem = wrapperElem.children[oldIndex] as HTMLElement; + if (newIndex > oldIndex) { + wrapperElem.insertBefore(targetThElem, oldThElem); + } else { + wrapperElem.insertBefore( + targetThElem, + oldThElem ? oldThElem.nextElementSibling : oldThElem + ); + } + return; + } + const currentRow = dynamicColumns.value.splice(oldIndex, 1)[0]; + dynamicColumns.value.splice(newIndex, 0, currentRow); + } + }); + }); + }; + + const isFixedColumn = (label: string) => { + return dynamicColumns.value.filter(item => item.label === label)[0].fixed + ? true + : false; + }; + + const rendTippyProps = (content: string) => { + // https://vue-tippy.netlify.app/props + return { + content, + offset: [0, 18], + duration: [300, 0], + followCursor: true, + hideOnClick: "toggle" + }; + }; + + const reference = { + reference: () => ( + <SettingIcon + class={["w-[16px]", iconClass.value]} + v-tippy={rendTippyProps("鍒楄缃�")} + /> + ) + }; + + return () => ( + <> + <div + {...attrs} + class={[ + "w-full", + "px-2", + "pb-2", + "bg-bg_color", + isFullscreen.value + ? ["h-full!", "z-2002", "fixed", "inset-0"] + : "mt-2" + ]} + > + <div class="flex justify-between w-full h-[60px] p-4"> + {slots?.title ? ( + slots.title() + ) : ( + <p class="font-bold truncate">{props.title}</p> + )} + <div class="flex items-center justify-around"> + {slots?.buttons ? ( + <div class="flex mr-4">{slots.buttons()}</div> + ) : null} + {props.tableRef?.size ? ( + <> + <ExpandIcon + class={["w-[16px]", iconClass.value]} + style={{ + transform: isExpandAll.value ? "none" : "rotate(-90deg)" + }} + v-tippy={rendTippyProps( + isExpandAll.value ? "鎶樺彔" : "灞曞紑" + )} + onClick={() => onExpand()} + /> + <el-divider direction="vertical" /> + </> + ) : null} + <RefreshIcon + class={[ + "w-[16px]", + iconClass.value, + loading.value ? "animate-spin" : "" + ]} + v-tippy={rendTippyProps("鍒锋柊")} + onClick={() => onReFresh()} + /> + <el-divider direction="vertical" /> + <el-dropdown + v-slots={dropdown} + trigger="click" + v-tippy={rendTippyProps("瀵嗗害")} + > + <CollapseIcon class={["w-[16px]", iconClass.value]} /> + </el-dropdown> + <el-divider direction="vertical" /> + + <el-popover + v-slots={reference} + placement="bottom-start" + popper-style={{ padding: 0 }} + width="200" + trigger="click" + > + <div class={[topClass.value]}> + <el-checkbox + class="-mr-1!" + label="鍒楀睍绀�" + v-model={checkAll.value} + indeterminate={isIndeterminate.value} + onChange={value => handleCheckAllChange(value)} + /> + <el-button type="primary" link onClick={() => onReset()}> + 閲嶇疆 + </el-button> + </div> + + <div class="pt-[6px] pl-[11px]"> + <el-scrollbar max-height="36vh"> + <el-checkbox-group + ref={`GroupRef${unref(props.tableKey)}`} + modelValue={checkedColumns.value} + onChange={value => handleCheckedColumnsChange(value)} + > + <el-space + direction="vertical" + alignment="flex-start" + size={0} + > + {checkColumnList.map((item, index) => { + return ( + <div class="flex items-center"> + <DragIcon + class={[ + "drag-btn w-[16px] mr-2", + isFixedColumn(item) + ? "cursor-no-drop!" + : "cursor-grab!" + ]} + onMouseenter={(event: { + preventDefault: () => void; + }) => rowDrop(event)} + /> + <el-checkbox + key={index} + label={item} + value={item} + onChange={value => + handleCheckColumnListChange(value, item) + } + > + <span + title={item} + class="inline-block w-[120px] truncate hover:text-text_color_primary" + > + {item} + </span> + </el-checkbox> + </div> + ); + })} + </el-space> + </el-checkbox-group> + </el-scrollbar> + </div> + </el-popover> + <el-divider direction="vertical" /> + + <iconifyIconOffline + class={["w-[16px]", iconClass.value]} + icon={isFullscreen.value ? ExitFullscreen : Fullscreen} + v-tippy={isFullscreen.value ? "閫�鍑哄叏灞�" : "鍏ㄥ睆"} + onClick={() => onFullscreen()} + /> + </div> + </div> + {slots.default({ + size: size.value, + dynamicColumns: dynamicColumns.value + })} + </div> + </> + ); + } +}); diff --git a/src/components/ReSegmented/index.ts b/src/components/ReSegmented/index.ts new file mode 100644 index 0000000..de4253c --- /dev/null +++ b/src/components/ReSegmented/index.ts @@ -0,0 +1,8 @@ +import reSegmented from "./src/index"; +import { withInstall } from "@pureadmin/utils"; + +/** 鍒嗘鎺у埗鍣ㄧ粍浠� */ +export const ReSegmented = withInstall(reSegmented); + +export default ReSegmented; +export type { OptionsType } from "./src/type"; diff --git a/src/components/ReSegmented/src/index.css b/src/components/ReSegmented/src/index.css new file mode 100644 index 0000000..4fe79ef --- /dev/null +++ b/src/components/ReSegmented/src/index.css @@ -0,0 +1,156 @@ +.pure-segmented { + --pure-control-padding-horizontal: 12px; + --pure-control-padding-horizontal-sm: 8px; + --pure-segmented-track-padding: 2px; + --pure-segmented-line-width: 1px; + + --pure-segmented-border-radius-small: 4px; + --pure-segmented-border-radius-base: 6px; + --pure-segmented-border-radius-large: 8px; + + box-sizing: border-box; + display: inline-block; + padding: var(--pure-segmented-track-padding); + font-size: var(--el-font-size-base); + color: rgba(0, 0, 0, 0.65); + background-color: rgb(0 0 0 / 4%); + border-radius: var(--pure-segmented-border-radius-base); +} + +.pure-segmented-block { + display: flex; +} + +.pure-segmented-block .pure-segmented-item { + flex: 1; + min-width: 0; +} + +.pure-segmented-block .pure-segmented-item > .pure-segmented-item-label > span { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +/* small */ +.pure-segmented.pure-segmented--small { + border-radius: var(--pure-segmented-border-radius-small); +} +.pure-segmented.pure-segmented--small .pure-segmented-item { + border-radius: var(--el-border-radius-small); +} +.pure-segmented.pure-segmented--small .pure-segmented-item > div { + min-height: calc( + var(--el-component-size-small) - var(--pure-segmented-track-padding) * 2 + ); + line-height: calc( + var(--el-component-size-small) - var(--pure-segmented-track-padding) * 2 + ); + padding: 0 + calc( + var(--pure-control-padding-horizontal-sm) - + var(--pure-segmented-line-width) + ); +} + +/* large */ +.pure-segmented.pure-segmented--large { + border-radius: var(--pure-segmented-border-radius-large); +} +.pure-segmented.pure-segmented--large .pure-segmented-item { + border-radius: calc( + var(--el-border-radius-base) + var(--el-border-radius-small) + ); +} +.pure-segmented.pure-segmented--large .pure-segmented-item > div { + min-height: calc( + var(--el-component-size-large) - var(--pure-segmented-track-padding) * 2 + ); + line-height: calc( + var(--el-component-size-large) - var(--pure-segmented-track-padding) * 2 + ); + padding: 0 + calc( + var(--pure-control-padding-horizontal) - var(--pure-segmented-line-width) + ); + font-size: var(--el-font-size-medium); +} + +/* default */ +.pure-segmented-item { + position: relative; + text-align: center; + cursor: pointer; + border-radius: var(--el-border-radius-base); + transition: all 0.1s cubic-bezier(0.645, 0.045, 0.355, 1); +} +.pure-segmented .pure-segmented-item > div { + min-height: calc( + var(--el-component-size) - var(--pure-segmented-track-padding) * 2 + ); + line-height: calc( + var(--el-component-size) - var(--pure-segmented-track-padding) * 2 + ); + padding: 0 + calc( + var(--pure-control-padding-horizontal) - var(--pure-segmented-line-width) + ); + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.pure-segmented-group { + position: relative; + display: flex; + align-items: stretch; + justify-items: flex-start; + width: 100%; +} + +.pure-segmented-item-selected { + position: absolute; + top: 0; + left: 0; + box-sizing: border-box; + display: none; + width: 0; + height: 100%; + padding: 4px 0; + background-color: #fff; + border-radius: 4px; + box-shadow: + 0 2px 8px -2px rgb(0 0 0 / 5%), + 0 1px 4px -1px rgb(0 0 0 / 7%), + 0 0 1px rgb(0 0 0 / 7%); + transition: + transform 0.5s cubic-bezier(0.645, 0.045, 0.355, 1), + width 0.5s cubic-bezier(0.645, 0.045, 0.355, 1); + will-change: transform, width; +} + +.pure-segmented-item > input { + position: absolute; + inset-block-start: 0; + inset-inline-start: 0; + width: 0; + height: 0; + opacity: 0; + pointer-events: none; +} + +.pure-segmented-item-label { + display: flex; + align-items: center; + justify-content: center; +} + +.pure-segmented-item-icon svg { + width: 16px; + height: 16px; +} + +.pure-segmented-item-disabled { + color: rgba(0, 0, 0, 0.25); + cursor: not-allowed; +} diff --git a/src/components/ReSegmented/src/index.tsx b/src/components/ReSegmented/src/index.tsx new file mode 100644 index 0000000..39580ed --- /dev/null +++ b/src/components/ReSegmented/src/index.tsx @@ -0,0 +1,216 @@ +import "./index.css"; +import type { OptionsType } from "./type"; +import { useRenderIcon } from "@/components/ReIcon/src/hooks"; +import { + useDark, + isNumber, + isFunction, + useResizeObserver +} from "@pureadmin/utils"; +import { + type PropType, + h, + ref, + toRef, + watch, + nextTick, + defineComponent, + getCurrentInstance +} from "vue"; + +const props = { + options: { + type: Array<OptionsType>, + default: () => [] + }, + /** 榛樿閫変腑锛屾寜鐓х涓�涓储寮曚负 `0` 鐨勬ā寮忥紝鍙�夛紙`modelValue`鍙湁浼燻number`绫诲瀷鏃舵墠涓哄搷搴斿紡锛� */ + modelValue: { + type: undefined, + require: false, + default: "0" + }, + /** 灏嗗搴﹁皟鏁翠负鐖跺厓绱犲搴� */ + block: { + type: Boolean, + default: false + }, + /** 鎺т欢灏哄 */ + size: { + type: String as PropType<"small" | "default" | "large"> + }, + /** 鏄惁鍏ㄥ眬绂佺敤锛岄粯璁� `false` */ + disabled: { + type: Boolean, + default: false + }, + /** 褰撳唴瀹瑰彂鐢熷彉鍖栨椂锛岃缃� `resize` 鍙娇鍏惰嚜閫傚簲瀹瑰櫒浣嶇疆 */ + resize: { + type: Boolean, + default: false + } +}; + +export default defineComponent({ + name: "ReSegmented", + props, + emits: ["change", "update:modelValue"], + setup(props, { emit }) { + const width = ref(0); + const translateX = ref(0); + const { isDark } = useDark(); + const initStatus = ref(false); + const curMouseActive = ref(-1); + const segmentedItembg = ref(""); + const instance = getCurrentInstance()!; + const curIndex = isNumber(props.modelValue) + ? toRef(props, "modelValue") + : ref(0); + + function handleChange({ option, index }, event: Event) { + if (props.disabled || option.disabled) return; + event.preventDefault(); + isNumber(props.modelValue) + ? emit("update:modelValue", index) + : (curIndex.value = index); + segmentedItembg.value = ""; + emit("change", { index, option }); + } + + function handleMouseenter({ option, index }, event: Event) { + if (props.disabled) return; + event.preventDefault(); + curMouseActive.value = index; + if (option.disabled || curIndex.value === index) { + segmentedItembg.value = ""; + } else { + segmentedItembg.value = isDark.value + ? "#1f1f1f" + : "rgba(0, 0, 0, 0.06)"; + } + } + + function handleMouseleave(_, event: Event) { + if (props.disabled) return; + event.preventDefault(); + curMouseActive.value = -1; + } + + function handleInit(index = curIndex.value) { + nextTick(() => { + const curLabelRef = instance?.proxy?.$refs[`labelRef${index}`] as ElRef; + if (!curLabelRef) return; + width.value = curLabelRef.clientWidth; + translateX.value = curLabelRef.offsetLeft; + initStatus.value = true; + }); + } + + function handleResizeInit() { + useResizeObserver(".pure-segmented", () => { + nextTick(() => { + handleInit(curIndex.value); + }); + }); + } + + (props.block || props.resize) && handleResizeInit(); + + watch( + () => curIndex.value, + index => { + nextTick(() => { + handleInit(index); + }); + }, + { + immediate: true + } + ); + + watch(() => props.size, handleResizeInit, { + immediate: true + }); + + const rendLabel = () => { + return props.options.map((option, index) => { + return ( + <label + ref={`labelRef${index}`} + class={[ + "pure-segmented-item", + (props.disabled || option?.disabled) && + "pure-segmented-item-disabled" + ]} + style={{ + background: + curMouseActive.value === index ? segmentedItembg.value : "", + color: props.disabled + ? null + : !option.disabled && + (curIndex.value === index || curMouseActive.value === index) + ? isDark.value + ? "rgba(255, 255, 255, 0.85)" + : "rgba(0,0,0,.88)" + : "" + }} + onMouseenter={event => handleMouseenter({ option, index }, event)} + onMouseleave={event => handleMouseleave({ option, index }, event)} + onClick={event => handleChange({ option, index }, event)} + > + <input type="radio" name="segmented" /> + <div + class="pure-segmented-item-label" + v-tippy={{ + content: option?.tip, + zIndex: 41000 + }} + > + {option.icon && !isFunction(option.label) ? ( + <span + class="pure-segmented-item-icon" + style={{ marginRight: option.label ? "6px" : 0 }} + > + {h( + useRenderIcon(option.icon, { + ...option?.iconAttrs + }) + )} + </span> + ) : null} + {option.label ? ( + isFunction(option.label) ? ( + h(option.label) + ) : ( + <span>{option.label}</span> + ) + ) : null} + </div> + </label> + ); + }); + }; + + return () => ( + <div + class={{ + "pure-segmented": true, + "pure-segmented-block": props.block, + "pure-segmented--large": props.size === "large", + "pure-segmented--small": props.size === "small" + }} + > + <div class="pure-segmented-group"> + <div + class="pure-segmented-item-selected" + style={{ + width: `${width.value}px`, + transform: `translateX(${translateX.value}px)`, + display: initStatus.value ? "block" : "none" + }} + ></div> + {rendLabel()} + </div> + </div> + ); + } +}); diff --git a/src/components/ReSegmented/src/type.ts b/src/components/ReSegmented/src/type.ts new file mode 100644 index 0000000..6c29889 --- /dev/null +++ b/src/components/ReSegmented/src/type.ts @@ -0,0 +1,20 @@ +import type { VNode, Component } from "vue"; +import type { iconType } from "@/components/ReIcon/src/types.ts"; + +export interface OptionsType { + /** 鏂囧瓧 */ + label?: string | (() => VNode | Component); + /** + * @description 鍥炬爣锛岄噰鐢ㄥ钩鍙板唴缃殑 `useRenderIcon` 鍑芥暟娓叉煋 + * @see {@link 鐢ㄦ硶鍙傝�� https://pure-admin.cn/pages/icon/#%E9%80%9A%E7%94%A8%E5%9B%BE%E6%A0%87-userendericon-hooks } + */ + icon?: string | Component; + /** 鍥炬爣灞炴�с�佹牱寮忛厤缃� */ + iconAttrs?: iconType; + /** 鍊� */ + value?: any; + /** 鏄惁绂佺敤 */ + disabled?: boolean; + /** `tooltip` 鎻愮ず */ + tip?: string; +} diff --git a/src/components/ReText/index.ts b/src/components/ReText/index.ts new file mode 100644 index 0000000..6213566 --- /dev/null +++ b/src/components/ReText/index.ts @@ -0,0 +1,7 @@ +import reText from "./src/index.vue"; +import { withInstall } from "@pureadmin/utils"; + +/** 鏀寔`Tooltip`鎻愮ず鐨勬枃鏈渷鐣ョ粍浠� */ +export const ReText = withInstall(reText); + +export default ReText; diff --git a/src/components/ReText/src/index.vue b/src/components/ReText/src/index.vue new file mode 100644 index 0000000..4c4a232 --- /dev/null +++ b/src/components/ReText/src/index.vue @@ -0,0 +1,69 @@ +<script setup lang="ts"> +import { h, onMounted, ref } from "vue"; +import { type TippyOptions, type TippyContent, useTippy } from "vue-tippy"; + +defineOptions({ + name: "ReText" +}); + +const props = defineProps({ + // 琛屾暟 + lineClamp: { + type: [String, Number] + }, + tippyProps: { + type: Object as PropType<TippyOptions>, + default: () => ({}) + } +}); + +const slots = defineSlots<{ + content: () => TippyContent; + default: () => any; +}>(); + +const textRef = ref(); +const tippyFunc = ref(); + +const isTextEllipsis = (el: HTMLElement) => { + if (!props.lineClamp) { + // 鍗曡鐪佺暐鍒ゆ柇 + return el.scrollWidth > el.clientWidth; + } else { + // 澶氳鐪佺暐鍒ゆ柇 + return el.scrollHeight > el.clientHeight; + } +}; + +const getTippyProps = () => ({ + content: h(slots.content || slots.default), + ...props.tippyProps +}); + +function handleHover(event: MouseEvent) { + if (isTextEllipsis(event.target as HTMLElement)) { + tippyFunc.value.setProps(getTippyProps()); + tippyFunc.value.enable(); + } else { + tippyFunc.value.disable(); + } +} + +onMounted(() => { + tippyFunc.value = useTippy(textRef.value?.$el, getTippyProps()); +}); +</script> + +<template> + <el-text + v-bind="{ + truncated: !lineClamp, + lineClamp, + ...$attrs + }" + ref="textRef" + @mouseover.self="handleHover" + > + <slot /> + </el-text> +</template> diff --git a/src/config/index.ts b/src/config/index.ts new file mode 100644 index 0000000..c81d1c4 --- /dev/null +++ b/src/config/index.ts @@ -0,0 +1,55 @@ +import axios from "axios"; +import type { App } from "vue"; + +let config: object = {}; +const { VITE_PUBLIC_PATH } = import.meta.env; + +const setConfig = (cfg?: unknown) => { + config = Object.assign(config, cfg); +}; + +const getConfig = (key?: string): PlatformConfigs => { + if (typeof key === "string") { + const arr = key.split("."); + if (arr && arr.length) { + let data = config; + arr.forEach(v => { + if (data && typeof data[v] !== "undefined") { + data = data[v]; + } else { + data = null; + } + }); + return data; + } + } + return config; +}; + +/** 鑾峰彇椤圭洰鍔ㄦ�佸叏灞�閰嶇疆 */ +export const getPlatformConfig = async (app: App): Promise<undefined> => { + app.config.globalProperties.$config = getConfig(); + return axios({ + method: "get", + url: `${VITE_PUBLIC_PATH}platform-config.json` + }) + .then(({ data: config }) => { + let $config = app.config.globalProperties.$config; + // 鑷姩娉ㄥ叆绯荤粺閰嶇疆 + if (app && $config && typeof config === "object") { + $config = Object.assign($config, config); + app.config.globalProperties.$config = $config; + // 璁剧疆鍏ㄥ眬閰嶇疆 + setConfig($config); + } + return $config; + }) + .catch(() => { + throw "璇峰湪public鏂囦欢澶逛笅娣诲姞platform-config.json閰嶇疆鏂囦欢"; + }); +}; + +/** 鏈湴鍝嶅簲寮忓瓨鍌ㄧ殑鍛藉悕绌洪棿 */ +const responsiveStorageNameSpace = () => getConfig().ResponsiveStorageNameSpace; + +export { getConfig, setConfig, responsiveStorageNameSpace }; diff --git a/src/directives/auth/index.ts b/src/directives/auth/index.ts new file mode 100644 index 0000000..2fc6490 --- /dev/null +++ b/src/directives/auth/index.ts @@ -0,0 +1,15 @@ +import { hasAuth } from "@/router/utils"; +import type { Directive, DirectiveBinding } from "vue"; + +export const auth: Directive = { + mounted(el: HTMLElement, binding: DirectiveBinding<string | Array<string>>) { + const { value } = binding; + if (value) { + !hasAuth(value) && el.parentNode?.removeChild(el); + } else { + throw new Error( + "[Directive: auth]: need auths! Like v-auth=\"['btn.add','btn.edit']\"" + ); + } + } +}; diff --git a/src/directives/copy/index.ts b/src/directives/copy/index.ts new file mode 100644 index 0000000..b71fa19 --- /dev/null +++ b/src/directives/copy/index.ts @@ -0,0 +1,33 @@ +import { message } from "@/utils/message"; +import { useEventListener } from "@vueuse/core"; +import { copyTextToClipboard } from "@pureadmin/utils"; +import type { Directive, DirectiveBinding } from "vue"; + +export interface CopyEl extends HTMLElement { + copyValue: string; +} + +/** 鏂囨湰澶嶅埗鎸囦护锛堥粯璁ゅ弻鍑诲鍒讹級 */ +export const copy: Directive = { + mounted(el: CopyEl, binding: DirectiveBinding<string>) { + const { value } = binding; + if (value) { + el.copyValue = value; + const arg = binding.arg ?? "dblclick"; + // Register using addEventListener on mounted, and removeEventListener automatically on unmounted + useEventListener(el, arg, () => { + const success = copyTextToClipboard(el.copyValue); + success + ? message("澶嶅埗鎴愬姛", { type: "success" }) + : message("澶嶅埗澶辫触", { type: "error" }); + }); + } else { + throw new Error( + '[Directive: copy]: need value! Like v-copy="modelValue"' + ); + } + }, + updated(el: CopyEl, binding: DirectiveBinding) { + el.copyValue = binding.value; + } +}; diff --git a/src/directives/index.ts b/src/directives/index.ts new file mode 100644 index 0000000..d01fe71 --- /dev/null +++ b/src/directives/index.ts @@ -0,0 +1,6 @@ +export * from "./auth"; +export * from "./copy"; +export * from "./longpress"; +export * from "./optimize"; +export * from "./perms"; +export * from "./ripple"; diff --git a/src/directives/longpress/index.ts b/src/directives/longpress/index.ts new file mode 100644 index 0000000..4eec6a2 --- /dev/null +++ b/src/directives/longpress/index.ts @@ -0,0 +1,63 @@ +import { useEventListener } from "@vueuse/core"; +import type { Directive, DirectiveBinding } from "vue"; +import { subBefore, subAfter, isFunction } from "@pureadmin/utils"; + +export const longpress: Directive = { + mounted(el: HTMLElement, binding: DirectiveBinding<Function>) { + const cb = binding.value; + if (cb && isFunction(cb)) { + let timer = null; + let interTimer = null; + let num = 500; + let interNum = null; + const isInter = binding?.arg?.includes(":") ?? false; + + if (isInter) { + num = Number(subBefore(binding.arg, ":")); + interNum = Number(subAfter(binding.arg, ":")); + } else if (binding.arg) { + num = Number(binding.arg); + } + + const clear = () => { + if (timer) { + clearTimeout(timer); + timer = null; + } + if (interTimer) { + clearInterval(interTimer); + interTimer = null; + } + }; + + const onDownInter = (ev: PointerEvent) => { + ev.preventDefault(); + if (interTimer === null) { + interTimer = setInterval(() => cb(), interNum); + } + }; + + const onDown = (ev: PointerEvent) => { + clear(); + ev.preventDefault(); + if (timer === null) { + timer = isInter + ? setTimeout(() => { + cb(); + onDownInter(ev); + }, num) + : setTimeout(() => cb(), num); + } + }; + + // Register using addEventListener on mounted, and removeEventListener automatically on unmounted + useEventListener(el, "pointerdown", onDown); + useEventListener(el, "pointerup", clear); + useEventListener(el, "pointerleave", clear); + } else { + throw new Error( + '[Directive: longpress]: need callback and callback must be a function! Like v-longpress="callback"' + ); + } + } +}; diff --git a/src/directives/optimize/index.ts b/src/directives/optimize/index.ts new file mode 100644 index 0000000..7b92538 --- /dev/null +++ b/src/directives/optimize/index.ts @@ -0,0 +1,68 @@ +import { + isArray, + throttle, + debounce, + isObject, + isFunction +} from "@pureadmin/utils"; +import { useEventListener } from "@vueuse/core"; +import type { Directive, DirectiveBinding } from "vue"; + +export interface OptimizeOptions { + /** 浜嬩欢鍚� */ + event: string; + /** 浜嬩欢瑙﹀彂鐨勬柟娉� */ + fn: (...params: any) => any; + /** 鏄惁绔嬪嵆鎵ц */ + immediate?: boolean; + /** 闃叉姈鎴栬妭娴佺殑寤惰繜鏃堕棿锛堥槻鎶栭粯璁わ細`200`姣銆佽妭娴侀粯璁わ細`1000`姣锛� */ + timeout?: number; + /** 浼犻�掔殑鍙傛暟 */ + params?: any; +} + +/** 闃叉姈锛坴-optimize鎴杤-optimize:debounce锛夈�佽妭娴侊紙v-optimize:throttle锛夋寚浠� */ +export const optimize: Directive = { + mounted(el: HTMLElement, binding: DirectiveBinding<OptimizeOptions>) { + const { value } = binding; + const optimizeType = binding.arg ?? "debounce"; + const type = ["debounce", "throttle"].find(t => t === optimizeType); + if (type) { + if (value && value.event && isFunction(value.fn)) { + let params = value?.params; + if (params) { + if (isArray(params) || isObject(params)) { + params = isObject(params) ? Array.of(params) : params; + } else { + throw new Error( + "[Directive: optimize]: `params` must be an array or object" + ); + } + } + // Register using addEventListener on mounted, and removeEventListener automatically on unmounted + useEventListener( + el, + value.event, + type === "debounce" + ? debounce( + params ? () => value.fn(...params) : value.fn, + value?.timeout ?? 200, + value?.immediate ?? false + ) + : throttle( + params ? () => value.fn(...params) : value.fn, + value?.timeout ?? 1000 + ) + ); + } else { + throw new Error( + "[Directive: optimize]: `event` and `fn` are required, and `fn` must be a function" + ); + } + } else { + throw new Error( + "[Directive: optimize]: only `debounce` and `throttle` are supported" + ); + } + } +}; diff --git a/src/directives/perms/index.ts b/src/directives/perms/index.ts new file mode 100644 index 0000000..073c918 --- /dev/null +++ b/src/directives/perms/index.ts @@ -0,0 +1,15 @@ +import { hasPerms } from "@/utils/auth"; +import type { Directive, DirectiveBinding } from "vue"; + +export const perms: Directive = { + mounted(el: HTMLElement, binding: DirectiveBinding<string | Array<string>>) { + const { value } = binding; + if (value) { + !hasPerms(value) && el.parentNode?.removeChild(el); + } else { + throw new Error( + "[Directive: perms]: need perms! Like v-perms=\"['btn.add','btn.edit']\"" + ); + } + } +}; diff --git a/src/directives/ripple/index.scss b/src/directives/ripple/index.scss new file mode 100644 index 0000000..061c82c --- /dev/null +++ b/src/directives/ripple/index.scss @@ -0,0 +1,48 @@ +/* stylelint-disable-next-line scss/dollar-variable-colon-space-after */ +$ripple-animation-transition-in: + transform 0.4s cubic-bezier(0, 0, 0.2, 1), + opacity 0.2s cubic-bezier(0, 0, 0.2, 1) !default; +$ripple-animation-transition-out: opacity 0.5s cubic-bezier(0, 0, 0.2, 1) !default; +$ripple-animation-visible-opacity: 0.25 !default; + +.v-ripple { + &__container { + position: absolute; + top: 0; + left: 0; + z-index: 0; + width: 100%; + height: 100%; + overflow: hidden; + pointer-events: none; + border-radius: inherit; + contain: strict; + } + + &__animation { + position: absolute; + top: 0; + left: 0; + overflow: hidden; + pointer-events: none; + background: currentcolor; + border-radius: 50%; + opacity: 0; + will-change: transform, opacity; + + &--enter { + opacity: 0; + transition: none; + } + + &--in { + opacity: $ripple-animation-visible-opacity; + transition: $ripple-animation-transition-in; + } + + &--out { + opacity: 0; + transition: $ripple-animation-transition-out; + } + } +} diff --git a/src/directives/ripple/index.ts b/src/directives/ripple/index.ts new file mode 100644 index 0000000..8aef2d1 --- /dev/null +++ b/src/directives/ripple/index.ts @@ -0,0 +1,229 @@ +import "./index.scss"; +import { isObject } from "@pureadmin/utils"; +import type { Directive, DirectiveBinding } from "vue"; + +export interface RippleOptions { + /** 鑷畾涔塦ripple`棰滆壊锛屾敮鎸乣tailwindcss` */ + class?: string; + /** 鏄惁浠庝腑蹇冩墿鏁� */ + center?: boolean; + circle?: boolean; +} + +export interface RippleDirectiveBinding + extends Omit<DirectiveBinding, "modifiers" | "value"> { + value?: boolean | { class: string }; + modifiers: { + center?: boolean; + circle?: boolean; + }; +} + +function transform(el: HTMLElement, value: string) { + el.style.transform = value; + el.style.webkitTransform = value; +} + +const calculate = ( + e: PointerEvent, + el: HTMLElement, + value: RippleOptions = {} +) => { + const offset = el.getBoundingClientRect(); + + // 鑾峰彇鐐瑰嚮浣嶇疆璺濈 el 鐨勫瀭鐩村拰姘村钩璺濈 + const localX = e.clientX - offset.left; + const localY = e.clientY - offset.top; + + let radius = 0; + let scale = 0.3; + // 璁$畻鐐瑰嚮浣嶇疆鍒� el 椤剁偣鏈�杩滆窛绂伙紝鍗充负鍦嗙殑鏈�澶у崐寰勶紙鍕捐偂瀹氱悊锛� + if (el._ripple?.circle) { + scale = 0.15; + radius = el.clientWidth / 2; + radius = value.center + ? radius + : radius + Math.sqrt((localX - radius) ** 2 + (localY - radius) ** 2) / 4; + } else { + radius = Math.sqrt(el.clientWidth ** 2 + el.clientHeight ** 2) / 2; + } + + // 涓績鐐瑰潗鏍� + const centerX = `${(el.clientWidth - radius * 2) / 2}px`; + const centerY = `${(el.clientHeight - radius * 2) / 2}px`; + + // 鐐瑰嚮浣嶇疆鍧愭爣 + const x = value.center ? centerX : `${localX - radius}px`; + const y = value.center ? centerY : `${localY - radius}px`; + + return { radius, scale, x, y, centerX, centerY }; +}; + +const ripples = { + show(e: PointerEvent, el: HTMLElement, value: RippleOptions = {}) { + if (!el?._ripple?.enabled) { + return; + } + + // 鍒涘缓 ripple 鍏冪礌鍜� ripple 鐖跺厓绱� + const container = document.createElement("span"); + const animation = document.createElement("span"); + + container.appendChild(animation); + container.className = "v-ripple__container"; + + if (value.class) { + container.className += ` ${value.class}`; + } + + const { radius, scale, x, y, centerX, centerY } = calculate(e, el, value); + + // ripple 鍦嗗ぇ灏� + const size = `${radius * 2}px`; + + animation.className = "v-ripple__animation"; + animation.style.width = size; + animation.style.height = size; + + el.appendChild(container); + + // 鑾峰彇鐩爣鍏冪礌鏍峰紡琛� + const computed = window.getComputedStyle(el); + // 闃叉 position 琚鐩栧鑷� ripple 浣嶇疆鏈夐棶棰� + if (computed && computed.position === "static") { + el.style.position = "relative"; + el.dataset.previousPosition = "static"; + } + + animation.classList.add("v-ripple__animation--enter"); + animation.classList.add("v-ripple__animation--visible"); + transform( + animation, + `translate(${x}, ${y}) scale3d(${scale},${scale},${scale})` + ); + animation.dataset.activated = String(performance.now()); + + setTimeout(() => { + animation.classList.remove("v-ripple__animation--enter"); + animation.classList.add("v-ripple__animation--in"); + transform(animation, `translate(${centerX}, ${centerY}) scale3d(1,1,1)`); + }, 0); + }, + + hide(el: HTMLElement | null) { + if (!el?._ripple?.enabled) return; + + const ripples = el.getElementsByClassName("v-ripple__animation"); + + if (ripples.length === 0) return; + const animation = ripples[ripples.length - 1] as HTMLElement; + + if (animation.dataset.isHiding) return; + else animation.dataset.isHiding = "true"; + + const diff = performance.now() - Number(animation.dataset.activated); + const delay = Math.max(250 - diff, 0); + + setTimeout(() => { + animation.classList.remove("v-ripple__animation--in"); + animation.classList.add("v-ripple__animation--out"); + + setTimeout(() => { + const ripples = el.getElementsByClassName("v-ripple__animation"); + if (ripples.length === 1 && el.dataset.previousPosition) { + el.style.position = el.dataset.previousPosition; + delete el.dataset.previousPosition; + } + + if (animation.parentNode?.parentNode === el) + el.removeChild(animation.parentNode); + }, 300); + }, delay); + } +}; + +function isRippleEnabled(value: any): value is true { + return typeof value === "undefined" || !!value; +} + +function rippleShow(e: PointerEvent) { + const value: RippleOptions = {}; + const element = e.currentTarget as HTMLElement | undefined; + + if (!element?._ripple || element._ripple.touched) return; + + value.center = element._ripple.centered; + if (element._ripple.class) { + value.class = element._ripple.class; + } + + ripples.show(e, element, value); +} + +function rippleHide(e: Event) { + const element = e.currentTarget as HTMLElement | null; + if (!element?._ripple) return; + + window.setTimeout(() => { + if (element._ripple) { + element._ripple.touched = false; + } + }); + ripples.hide(element); +} + +function updateRipple( + el: HTMLElement, + binding: RippleDirectiveBinding, + wasEnabled: boolean +) { + const { value, modifiers } = binding; + const enabled = isRippleEnabled(value); + if (!enabled) { + ripples.hide(el); + } + + el._ripple = el._ripple ?? {}; + el._ripple.enabled = enabled; + el._ripple.centered = modifiers.center; + el._ripple.circle = modifiers.circle; + if (isObject(value) && value.class) { + el._ripple.class = value.class; + } + + if (enabled && !wasEnabled) { + el.addEventListener("pointerdown", rippleShow); + el.addEventListener("pointerup", rippleHide); + } else if (!enabled && wasEnabled) { + removeListeners(el); + } +} + +function removeListeners(el: HTMLElement) { + el.removeEventListener("pointerdown", rippleShow); + el.removeEventListener("pointerup", rippleHide); +} + +function mounted(el: HTMLElement, binding: RippleDirectiveBinding) { + updateRipple(el, binding, false); +} + +function unmounted(el: HTMLElement) { + delete el._ripple; + removeListeners(el); +} + +function updated(el: HTMLElement, binding: RippleDirectiveBinding) { + if (binding.value === binding.oldValue) { + return; + } + + const wasEnabled = isRippleEnabled(binding.oldValue); + updateRipple(el, binding, wasEnabled); +} + +export const Ripple: Directive = { + mounted, + unmounted, + updated +}; diff --git a/src/layout/components/lay-content/index.vue b/src/layout/components/lay-content/index.vue new file mode 100644 index 0000000..5c7ceb9 --- /dev/null +++ b/src/layout/components/lay-content/index.vue @@ -0,0 +1,213 @@ +<script setup lang="ts"> +import LayFrame from "../lay-frame/index.vue"; +import LayFooter from "../lay-footer/index.vue"; +import { useTags } from "@/layout/hooks/useTag"; +import { useGlobal, isNumber } from "@pureadmin/utils"; +import BackTopIcon from "@/assets/svg/back_top.svg?component"; +import { h, computed, Transition, defineComponent } from "vue"; +import { usePermissionStoreHook } from "@/store/modules/permission"; + +const props = defineProps({ + fixedHeader: Boolean +}); + +const { showModel } = useTags(); +const { $storage, $config } = useGlobal<GlobalPropertiesApi>(); + +const isKeepAlive = computed(() => { + return $config?.KeepAlive; +}); + +const transitions = computed(() => { + return route => { + return route.meta.transition; + }; +}); + +const hideTabs = computed(() => { + return $storage?.configure.hideTabs; +}); + +const hideFooter = computed(() => { + return $storage?.configure.hideFooter; +}); + +const stretch = computed(() => { + return $storage?.configure.stretch; +}); + +const layout = computed(() => { + return $storage?.layout.layout === "vertical"; +}); + +const getMainWidth = computed(() => { + return isNumber(stretch.value) + ? stretch.value + "px" + : stretch.value + ? "1440px" + : "100%"; +}); + +const getSectionStyle = computed(() => { + return [ + hideTabs.value && layout ? "padding-top: 48px;" : "", + !hideTabs.value && layout + ? showModel.value == "chrome" + ? "padding-top: 85px;" + : "padding-top: 81px;" + : "", + hideTabs.value && !layout.value ? "padding-top: 48px;" : "", + !hideTabs.value && !layout.value + ? showModel.value == "chrome" + ? "padding-top: 85px;" + : "padding-top: 81px;" + : "", + props.fixedHeader + ? "" + : `padding-top: 0;${ + hideTabs.value + ? "min-height: calc(100vh - 48px);" + : "min-height: calc(100vh - 86px);" + }` + ]; +}); + +const transitionMain = defineComponent({ + props: { + route: { + type: undefined, + required: true + } + }, + render() { + const transitionName = + transitions.value(this.route)?.name || "fade-transform"; + const enterTransition = transitions.value(this.route)?.enterTransition; + const leaveTransition = transitions.value(this.route)?.leaveTransition; + return h( + Transition, + { + name: enterTransition ? "pure-classes-transition" : transitionName, + enterActiveClass: enterTransition + ? `animate__animated ${enterTransition}` + : undefined, + leaveActiveClass: leaveTransition + ? `animate__animated ${leaveTransition}` + : undefined, + mode: "out-in", + appear: true + }, + { + default: () => [this.$slots.default()] + } + ); + } +}); +</script> + +<template> + <section + :class="[fixedHeader ? 'app-main' : 'app-main-nofixed-header']" + :style="getSectionStyle" + > + <router-view> + <template #default="{ Component, route }"> + <LayFrame :currComp="Component" :currRoute="route"> + <template #default="{ Comp, fullPath, frameInfo }"> + <el-scrollbar + v-if="fixedHeader" + :wrap-style="{ + display: 'flex', + 'flex-wrap': 'wrap', + 'max-width': getMainWidth, + margin: '0 auto', + transition: 'all 300ms cubic-bezier(0.4, 0, 0.2, 1)' + }" + :view-style="{ + display: 'flex', + flex: 'auto', + overflow: 'hidden', + 'flex-direction': 'column' + }" + > + <el-backtop + title="鍥炲埌椤堕儴" + target=".app-main .el-scrollbar__wrap" + > + <BackTopIcon /> + </el-backtop> + <div class="grow"> + <transitionMain :route="route"> + <keep-alive + v-if="isKeepAlive" + :include="usePermissionStoreHook().cachePageList" + > + <component + :is="Comp" + :key="fullPath" + :frameInfo="frameInfo" + class="main-content" + /> + </keep-alive> + <component + :is="Comp" + v-else + :key="fullPath" + :frameInfo="frameInfo" + class="main-content" + /> + </transitionMain> + </div> + <LayFooter v-if="!hideFooter" /> + </el-scrollbar> + <div v-else class="grow"> + <transitionMain :route="route"> + <keep-alive + v-if="isKeepAlive" + :include="usePermissionStoreHook().cachePageList" + > + <component + :is="Comp" + :key="fullPath" + :frameInfo="frameInfo" + class="main-content" + /> + </keep-alive> + <component + :is="Comp" + v-else + :key="fullPath" + :frameInfo="frameInfo" + class="main-content" + /> + </transitionMain> + </div> + </template> + </LayFrame> + </template> + </router-view> + + <!-- 椤佃剼 --> + <LayFooter v-if="!hideFooter && !fixedHeader" /> + </section> +</template> + +<style scoped> +.app-main { + position: relative; + width: 100%; + height: 100vh; + overflow-x: hidden; +} + +.app-main-nofixed-header { + position: relative; + display: flex; + flex-direction: column; + width: 100%; +} + +.main-content { + margin: 24px; +} +</style> diff --git a/src/layout/components/lay-footer/index.vue b/src/layout/components/lay-footer/index.vue new file mode 100644 index 0000000..b265daf --- /dev/null +++ b/src/layout/components/lay-footer/index.vue @@ -0,0 +1,31 @@ +<script setup lang="ts"> +import { getConfig } from "@/config"; + +const TITLE = getConfig("Title"); +</script> + +<template> + <footer + class="layout-footer text-[rgba(0,0,0,0.6)] dark:text-[rgba(220,220,242,0.8)]" + > + Copyright 漏 2020-present + <a + class="hover:text-primary" + href="https://github.com/pure-admin" + target="_blank" + > + {{ TITLE }} + </a> + </footer> +</template> + +<style lang="scss" scoped> +.layout-footer { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + padding: 0 0 8px; + font-size: 14px; +} +</style> diff --git a/src/layout/components/lay-frame/index.vue b/src/layout/components/lay-frame/index.vue new file mode 100644 index 0000000..b2bb9d5 --- /dev/null +++ b/src/layout/components/lay-frame/index.vue @@ -0,0 +1,79 @@ +<script setup lang="ts"> +import { getConfig } from "@/config"; +import { useMultiFrame } from "@/layout/hooks/useMultiFrame"; +import { useMultiTagsStoreHook } from "@/store/modules/multiTags"; +import { type Component, shallowRef, watch, computed } from "vue"; +import { type RouteRecordRaw, RouteLocationNormalizedLoaded } from "vue-router"; + +const props = defineProps<{ + currRoute: RouteLocationNormalizedLoaded; + currComp: Component; +}>(); + +const compList = shallowRef([]); +const { setMap, getMap, MAP, delMap } = useMultiFrame(); + +const keep = computed(() => { + return ( + getConfig().KeepAlive && + props.currRoute.meta?.keepAlive && + !!props.currRoute.meta?.frameSrc + ); +}); +// 閬垮厤閲嶆柊娓叉煋 LayFrame +const normalComp = computed(() => !keep.value && props.currComp); + +watch(useMultiTagsStoreHook().multiTags, (tags: any) => { + if (!Array.isArray(tags) || !keep.value) { + return; + } + const iframeTags = tags.filter(i => i.meta?.frameSrc); + // tags蹇呴』鏄皬浜嶮AP锛屾墠鏄仛浜嗗叧闂姩浣滐紝鍥犱负MAP鎻掑叆鐨勯『搴忓湪tags鍙樺寲鍚庡彂鐢� + if (iframeTags.length < MAP.size) { + for (const i of MAP.keys()) { + if (!tags.some(s => s.path === i)) { + delMap(i); + compList.value = getMap(); + } + } + } +}); + +watch( + () => props.currRoute.fullPath, + path => { + const multiTags = useMultiTagsStoreHook().multiTags as RouteRecordRaw[]; + const iframeTags = multiTags.filter(i => i.meta?.frameSrc); + if (keep.value) { + if (iframeTags.length !== MAP.size) { + const sameKey = [...MAP.keys()].find(i => path === i); + if (!sameKey) { + // 娣诲姞缂撳瓨 + setMap(path, props.currComp); + } + } + } + + if (MAP.size > 0) { + compList.value = getMap(); + } + }, + { + immediate: true + } +); +</script> +<template> + <template v-for="[fullPath, Comp] in compList" :key="fullPath"> + <div v-show="fullPath === currRoute.fullPath" class="w-full h-full"> + <slot + :fullPath="fullPath" + :Comp="Comp" + :frameInfo="{ frameSrc: currRoute.meta?.frameSrc, fullPath }" + /> + </div> + </template> + <div v-show="!keep" class="w-full h-full"> + <slot :Comp="normalComp" :fullPath="currRoute.fullPath" frameInfo /> + </div> +</template> diff --git a/src/layout/components/lay-navbar/index.vue b/src/layout/components/lay-navbar/index.vue new file mode 100644 index 0000000..21fd10f --- /dev/null +++ b/src/layout/components/lay-navbar/index.vue @@ -0,0 +1,135 @@ +<script setup lang="ts"> +import { useNav } from "@/layout/hooks/useNav"; +import LaySearch from "../lay-search/index.vue"; +import LayNotice from "../lay-notice/index.vue"; +import LayNavMix from "../lay-sidebar/NavMix.vue"; +import LaySidebarFullScreen from "../lay-sidebar/components/SidebarFullScreen.vue"; +import LaySidebarBreadCrumb from "../lay-sidebar/components/SidebarBreadCrumb.vue"; +import LaySidebarTopCollapse from "../lay-sidebar/components/SidebarTopCollapse.vue"; + +import LogoutCircleRLine from "~icons/ri/logout-circle-r-line"; +import Setting from "~icons/ri/settings-3-line"; + +const { + layout, + device, + logout, + onPanel, + pureApp, + username, + userAvatar, + avatarsStyle, + toggleSideBar +} = useNav(); +</script> + +<template> + <div class="navbar bg-[#fff] shadow-xs shadow-[rgba(0,21,41,0.08)]"> + <LaySidebarTopCollapse + v-if="device === 'mobile'" + class="hamburger-container" + :is-active="pureApp.sidebar.opened" + @toggleClick="toggleSideBar" + /> + + <LaySidebarBreadCrumb + v-if="layout !== 'mix' && device !== 'mobile'" + class="breadcrumb-container" + /> + + <LayNavMix v-if="layout === 'mix'" /> + + <div v-if="layout === 'vertical'" class="vertical-header-right"> + <!-- 鑿滃崟鎼滅储 --> + <LaySearch id="header-search" /> + <!-- 鍏ㄥ睆 --> + <LaySidebarFullScreen id="full-screen" /> + <!-- 娑堟伅閫氱煡 --> + <LayNotice id="header-notice" /> + <!-- 閫�鍑虹櫥褰� --> + <el-dropdown trigger="click"> + <span class="el-dropdown-link navbar-bg-hover select-none"> + <img :src="userAvatar" :style="avatarsStyle" /> + <p v-if="username" class="dark:text-white">{{ username }}</p> + </span> + <template #dropdown> + <el-dropdown-menu class="logout"> + <el-dropdown-item @click="logout"> + <IconifyIconOffline + :icon="LogoutCircleRLine" + style="margin: 5px" + /> + 閫�鍑虹郴缁� + </el-dropdown-item> + </el-dropdown-menu> + </template> + </el-dropdown> + <span + class="set-icon navbar-bg-hover" + title="鎵撳紑绯荤粺閰嶇疆" + @click="onPanel" + > + <IconifyIconOffline :icon="Setting" /> + </span> + </div> + </div> +</template> + +<style lang="scss" scoped> +.navbar { + width: 100%; + height: 48px; + overflow: hidden; + + .hamburger-container { + float: left; + height: 100%; + line-height: 48px; + cursor: pointer; + } + + .vertical-header-right { + display: flex; + align-items: center; + justify-content: flex-end; + min-width: 280px; + height: 48px; + color: #000000d9; + + .el-dropdown-link { + display: flex; + align-items: center; + justify-content: space-around; + height: 48px; + padding: 10px; + color: #000000d9; + cursor: pointer; + + p { + font-size: 14px; + } + + img { + width: 22px; + height: 22px; + border-radius: 50%; + } + } + } + + .breadcrumb-container { + float: left; + margin-left: 16px; + } +} + +.logout { + width: 120px; + + ::v-deep(.el-dropdown-menu__item) { + display: inline-flex; + flex-wrap: wrap; + min-width: 100%; + } +} +</style> diff --git a/src/layout/components/lay-notice/components/NoticeItem.vue b/src/layout/components/lay-notice/components/NoticeItem.vue new file mode 100644 index 0000000..4608e6f --- /dev/null +++ b/src/layout/components/lay-notice/components/NoticeItem.vue @@ -0,0 +1,177 @@ +<script setup lang="ts"> +import { ListItem } from "../data"; +import { ref, PropType, nextTick } from "vue"; +import { useNav } from "@/layout/hooks/useNav"; +import { deviceDetection } from "@pureadmin/utils"; + +defineProps({ + noticeItem: { + type: Object as PropType<ListItem>, + default: () => {} + } +}); + +const titleRef = ref(null); +const titleTooltip = ref(false); +const descriptionRef = ref(null); +const descriptionTooltip = ref(false); +const { tooltipEffect } = useNav(); +const isMobile = deviceDetection(); + +function hoverTitle() { + nextTick(() => { + titleRef.value?.scrollWidth > titleRef.value?.clientWidth + ? (titleTooltip.value = true) + : (titleTooltip.value = false); + }); +} + +function hoverDescription(event, description) { + // currentWidth 涓烘枃鏈湪椤甸潰涓墍鍗犵殑瀹藉害锛屽垱寤烘爣绛撅紝鍔犲叆鍒伴〉闈紝鑾峰彇currentWidth ,鏈�鍚庡湪绉婚櫎 + const tempTag = document.createElement("span"); + tempTag.innerText = description; + tempTag.className = "getDescriptionWidth"; + document.querySelector("body").appendChild(tempTag); + const currentWidth = ( + document.querySelector(".getDescriptionWidth") as HTMLSpanElement + ).offsetWidth; + document.querySelector(".getDescriptionWidth").remove(); + + // cellWidth涓哄鍣ㄧ殑瀹藉害 + const cellWidth = event.target.offsetWidth; + + // 褰撴枃鏈搴﹀ぇ浜庡鍣ㄥ搴︿袱鍊嶆椂锛屼唬琛ㄦ枃鏈樉绀鸿秴杩囦袱琛� + currentWidth > 2 * cellWidth + ? (descriptionTooltip.value = true) + : (descriptionTooltip.value = false); +} +</script> + +<template> + <div + class="notice-container border-0 border-b-[1px] border-solid border-[#f0f0f0] dark:border-[#303030]" + > + <el-avatar + v-if="noticeItem.avatar" + :size="30" + :src="noticeItem.avatar" + class="notice-container-avatar" + /> + <div class="notice-container-text"> + <div class="notice-text-title text-[#000000d9] dark:text-white"> + <el-tooltip + popper-class="notice-title-popper" + :effect="tooltipEffect" + :disabled="!titleTooltip" + :content="noticeItem.title" + placement="top-start" + :enterable="!isMobile" + > + <div + ref="titleRef" + class="notice-title-content" + @mouseover="hoverTitle" + > + {{ noticeItem.title }} + </div> + </el-tooltip> + <el-tag + v-if="noticeItem?.extra" + :type="noticeItem?.status" + size="small" + class="notice-title-extra" + > + {{ noticeItem?.extra }} + </el-tag> + </div> + + <el-tooltip + popper-class="notice-title-popper" + :effect="tooltipEffect" + :disabled="!descriptionTooltip" + :content="noticeItem.description" + placement="top-start" + > + <div + ref="descriptionRef" + class="notice-text-description" + @mouseover="hoverDescription($event, noticeItem.description)" + > + {{ noticeItem.description }} + </div> + </el-tooltip> + <div class="notice-text-datetime text-[#00000073] dark:text-white"> + {{ noticeItem.datetime }} + </div> + </div> + </div> +</template> + +<style> +.notice-title-popper { + max-width: 238px; +} +</style> +<style lang="scss" scoped> +.notice-container { + display: flex; + align-items: flex-start; + justify-content: space-between; + padding: 12px 0; + + // border-bottom: 1px solid #f0f0f0; + + .notice-container-avatar { + margin-right: 16px; + background: #fff; + } + + .notice-container-text { + display: flex; + flex: 1; + flex-direction: column; + justify-content: space-between; + + .notice-text-title { + display: flex; + margin-bottom: 8px; + font-size: 14px; + font-weight: 400; + line-height: 1.5715; + cursor: pointer; + + .notice-title-content { + flex: 1; + width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .notice-title-extra { + float: right; + margin-top: -1.5px; + font-weight: 400; + } + } + + .notice-text-description, + .notice-text-datetime { + font-size: 12px; + line-height: 1.5715; + } + + .notice-text-description { + display: -webkit-box; + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + } + + .notice-text-datetime { + margin-top: 4px; + } + } +} +</style> diff --git a/src/layout/components/lay-notice/components/NoticeList.vue b/src/layout/components/lay-notice/components/NoticeList.vue new file mode 100644 index 0000000..8617345 --- /dev/null +++ b/src/layout/components/lay-notice/components/NoticeList.vue @@ -0,0 +1,23 @@ +<script setup lang="ts"> +import { PropType } from "vue"; +import { ListItem } from "../data"; +import NoticeItem from "./NoticeItem.vue"; + +defineProps({ + list: { + type: Array as PropType<Array<ListItem>>, + default: () => [] + }, + emptyText: { + type: String, + default: "" + } +}); +</script> + +<template> + <div v-if="list.length"> + <NoticeItem v-for="(item, index) in list" :key="index" :noticeItem="item" /> + </div> + <el-empty v-else :description="emptyText" /> +</template> diff --git a/src/layout/components/lay-notice/data.ts b/src/layout/components/lay-notice/data.ts new file mode 100644 index 0000000..5a07f4d --- /dev/null +++ b/src/layout/components/lay-notice/data.ts @@ -0,0 +1,97 @@ +export interface ListItem { + avatar: string; + title: string; + datetime: string; + type: string; + description: string; + status?: "primary" | "success" | "warning" | "info" | "danger"; + extra?: string; +} + +export interface TabItem { + key: string; + name: string; + list: ListItem[]; + emptyText: string; +} + +export const noticesData: TabItem[] = [ + { + key: "1", + name: "閫氱煡", + list: [], + emptyText: "鏆傛棤閫氱煡" + }, + { + key: "2", + name: "娑堟伅", + list: [ + { + avatar: "https://xiaoxian521.github.io/hyperlink/svg/smile1.svg", + title: "灏忛摥 璇勮浜嗕綘", + description: "璇氬湪浜庡績锛屼俊鍦ㄤ簬琛岋紝璇氫俊鍦ㄤ簬蹇冭鍚堜竴銆�", + datetime: "浠婂ぉ", + type: "2" + }, + { + avatar: "https://xiaoxian521.github.io/hyperlink/svg/smile2.svg", + title: "鏉庣櫧 鍥炲浜嗕綘", + description: "闀块鐮存氮浼氭湁鏃讹紝鐩存寕浜戝竼娴庢钵娴枫��", + datetime: "鏄ㄥぉ", + type: "2" + }, + { + avatar: "https://xiaoxian521.github.io/hyperlink/svg/smile5.svg", + title: "鏍囬", + description: + "璇峰皢榧犳爣绉诲姩鍒版澶勶紝浠ヤ究娴嬭瘯瓒呴暱鐨勬秷鎭湪姝ゅ灏嗗浣曞鐞嗐�傛湰渚嬩腑璁剧疆鐨勬弿杩版渶澶ц鏁颁负2锛岃秴杩�2琛岀殑鎻忚堪鍐呭灏嗚鐪佺暐骞朵笖鍙互閫氳繃tooltip鏌ョ湅瀹屾暣鍐呭", + datetime: "鏃堕棿", + type: "2" + } + ], + emptyText: "鏆傛棤娑堟伅" + }, + { + key: "3", + name: "寰呭姙", + list: [ + { + avatar: "", + title: "绗笁鏂圭揣鎬ヤ唬鐮佸彉鏇�", + description: + "灏忔灄鎻愪氦浜� 2024-05-10锛岄渶鍦� 2024-05-11 鍓嶅畬鎴愪唬鐮佸彉鏇翠换鍔�", + datetime: "", + extra: "椹笂鍒版湡", + status: "danger", + type: "3" + }, + { + avatar: "", + title: "鐗堟湰鍙戝竷", + description: "鎸囨淳灏忛摥浜� 2024-06-18 鍓嶅畬鎴愭洿鏂板苟鍙戝竷", + datetime: "", + extra: "宸茶�楁椂 8 澶�", + status: "warning", + type: "3" + }, + { + avatar: "", + title: "鏂板姛鑳藉紑鍙�", + description: "寮�鍙戝绉熸埛绠$悊", + datetime: "", + extra: "杩涜涓�", + type: "3" + }, + { + avatar: "", + title: "浠诲姟鍚嶇О", + description: "浠诲姟闇�瑕佸湪 2030-10-30 10:00 鍓嶅惎鍔�", + datetime: "", + extra: "鏈紑濮�", + status: "info", + type: "3" + } + ], + emptyText: "鏆傛棤寰呭姙" + } +]; diff --git a/src/layout/components/lay-notice/index.vue b/src/layout/components/lay-notice/index.vue new file mode 100644 index 0000000..55baa69 --- /dev/null +++ b/src/layout/components/lay-notice/index.vue @@ -0,0 +1,96 @@ +<script setup lang="ts"> +import { ref, computed } from "vue"; +import { noticesData } from "./data"; +import NoticeList from "./components/NoticeList.vue"; +import BellIcon from "~icons/ep/bell"; + +const noticesNum = ref(0); +const notices = ref(noticesData); +const activeKey = ref(noticesData[0]?.key); + +notices.value.map(v => (noticesNum.value += v.list.length)); + +const getLabel = computed( + () => item => + item.name + (item.list.length > 0 ? `(${item.list.length})` : "") +); +</script> + +<template> + <el-dropdown trigger="click" placement="bottom-end"> + <span + :class="[ + 'dropdown-badge', + 'navbar-bg-hover', + 'select-none', + Number(noticesNum) !== 0 && 'mr-[10px]' + ]" + > + <el-badge :value="Number(noticesNum) === 0 ? '' : noticesNum" :max="99"> + <span class="header-notice-icon"> + <IconifyIconOffline :icon="BellIcon" /> + </span> + </el-badge> + </span> + <template #dropdown> + <el-dropdown-menu> + <el-tabs + v-model="activeKey" + :stretch="true" + class="dropdown-tabs" + :style="{ width: notices.length === 0 ? '200px' : '330px' }" + > + <el-empty + v-if="notices.length === 0" + description="鏆傛棤娑堟伅" + :image-size="60" + /> + <span v-else> + <template v-for="item in notices" :key="item.key"> + <el-tab-pane :label="getLabel(item)" :name="`${item.key}`"> + <el-scrollbar max-height="330px"> + <div class="noticeList-container"> + <NoticeList :list="item.list" :emptyText="item.emptyText" /> + </div> + </el-scrollbar> + </el-tab-pane> + </template> + </span> + </el-tabs> + </el-dropdown-menu> + </template> + </el-dropdown> +</template> + +<style lang="scss" scoped> +.dropdown-badge { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 48px; + cursor: pointer; + + .header-notice-icon { + font-size: 18px; + } +} + +.dropdown-tabs { + .noticeList-container { + padding: 15px 24px 0; + } + + :deep(.el-tabs__header) { + margin: 0; + } + + :deep(.el-tabs__nav-wrap)::after { + height: 1px; + } + + :deep(.el-tabs__nav-wrap) { + padding: 0 36px; + } +} +</style> diff --git a/src/layout/components/lay-panel/index.vue b/src/layout/components/lay-panel/index.vue new file mode 100644 index 0000000..b2d5bbe --- /dev/null +++ b/src/layout/components/lay-panel/index.vue @@ -0,0 +1,145 @@ +<script setup lang="ts"> +import { emitter } from "@/utils/mitt"; +import { onClickOutside } from "@vueuse/core"; +import { ref, computed, onMounted, onBeforeUnmount } from "vue"; +import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange"; +import CloseIcon from "~icons/ep/close"; + +const target = ref(null); +const show = ref<Boolean>(false); + +const iconClass = computed(() => { + return [ + "w-[22px]", + "h-[22px]", + "flex", + "justify-center", + "items-center", + "outline-hidden", + "rounded-[4px]", + "cursor-pointer", + "transition-colors", + "hover:bg-[#0000000f]", + "dark:hover:bg-[#ffffff1f]", + "dark:hover:text-[#ffffffd9]" + ]; +}); + +const { onReset } = useDataThemeChange(); + +onClickOutside(target, (event: any) => { + if (event.clientX > target.value.offsetLeft) return; + show.value = false; +}); + +onMounted(() => { + emitter.on("openPanel", () => { + show.value = true; + }); +}); + +onBeforeUnmount(() => { + // 瑙g粦`openPanel`鍏叡浜嬩欢锛岄槻姝㈠娆¤Е鍙� + emitter.off("openPanel"); +}); +</script> + +<template> + <div :class="{ show }"> + <div class="right-panel-background" /> + <div ref="target" class="right-panel bg-bg_color"> + <div + class="project-configuration border-0 border-b-[1px] border-solid border-[var(--pure-border-color)]" + > + <h4 class="dark:text-white">绯荤粺閰嶇疆</h4> + <span + v-tippy="{ + content: '鍏抽棴閰嶇疆', + placement: 'bottom-start', + zIndex: 41000 + }" + :class="iconClass" + > + <IconifyIconOffline + class="dark:text-white" + width="18px" + height="18px" + :icon="CloseIcon" + @click="show = !show" + /> + </span> + </div> + <el-scrollbar> + <slot /> + </el-scrollbar> + + <div + class="flex justify-end p-3 border-0 border-t-[1px] border-solid border-[var(--pure-border-color)]" + > + <el-button + v-tippy="{ + content: '娓呯┖缂撳瓨骞惰繑鍥炵櫥褰曢〉', + placement: 'left-start', + zIndex: 41000 + }" + type="danger" + text + bg + @click="onReset" + > + 娓呯┖缂撳瓨 + </el-button> + </div> + </div> + </div> +</template> + +<style lang="scss" scoped> +:deep(.el-scrollbar) { + height: calc(100vh - 110px); +} + +.right-panel-background { + position: fixed; + top: 0; + left: 0; + z-index: -1; + background: rgb(0 0 0 / 20%); + opacity: 0; + transition: opacity 0.3s cubic-bezier(0.7, 0.3, 0.1, 1); +} + +.right-panel { + position: fixed; + top: 0; + right: 0; + z-index: 40000; + width: 100%; + max-width: 280px; + box-shadow: 0 0 15px 0 rgb(0 0 0 / 5%); + transform: translate(100%); + transition: all 0.25s cubic-bezier(0.7, 0.3, 0.1, 1); +} + +.show { + transition: all 0.3s cubic-bezier(0.7, 0.3, 0.1, 1); + + .right-panel-background { + z-index: 20000; + width: 100%; + height: 100%; + opacity: 1; + } + + .right-panel { + transform: translate(0); + } +} + +.project-configuration { + display: flex; + align-items: center; + justify-content: space-between; + padding: 14px 20px; +} +</style> diff --git a/src/layout/components/lay-search/components/SearchFooter.vue b/src/layout/components/lay-search/components/SearchFooter.vue new file mode 100644 index 0000000..ebac0e7 --- /dev/null +++ b/src/layout/components/lay-search/components/SearchFooter.vue @@ -0,0 +1,61 @@ +<script setup lang="ts"> +import { useNav } from "@/layout/hooks/useNav"; +import MdiKeyboardEsc from "@/assets/svg/keyboard_esc.svg?component"; +import EnterOutlined from "@/assets/svg/enter_outlined.svg?component"; +import ArrowUpLine from "~icons/ri/arrow-up-line"; +import ArrowDownLine from "~icons/ri/arrow-down-line"; + +withDefaults(defineProps<{ total?: number }>(), { + total: 0 +}); + +const { device } = useNav(); +</script> + +<template> + <div class="search-footer text-[#333] dark:text-white"> + <span class="search-footer-item"> + <EnterOutlined class="icon" /> + 纭 + </span> + <span class="search-footer-item"> + <IconifyIconOffline :icon="ArrowUpLine" class="icon" /> + <IconifyIconOffline :icon="ArrowDownLine" class="icon" /> + 鍒囨崲 + </span> + <span class="search-footer-item"> + <MdiKeyboardEsc class="icon" /> + 鍏抽棴 + </span> + <p v-if="device !== 'mobile' && total > 0" class="search-footer-total"> + {{ `鍏� ${total} 椤筦 }} + </p> + </div> +</template> + +<style lang="scss" scoped> +.search-footer { + display: flex; + + .search-footer-item { + display: flex; + align-items: center; + margin-right: 14px; + } + + .icon { + padding: 2px; + margin-right: 3px; + font-size: 20px; + box-shadow: + inset 0 -2px #cdcde6, + inset 0 0 1px 1px #fff, + 0 1px 2px 1px #1e235a66; + } + + .search-footer-total { + position: absolute; + right: 20px; + } +} +</style> diff --git a/src/layout/components/lay-search/components/SearchHistory.vue b/src/layout/components/lay-search/components/SearchHistory.vue new file mode 100644 index 0000000..dd5875a --- /dev/null +++ b/src/layout/components/lay-search/components/SearchHistory.vue @@ -0,0 +1,198 @@ +<script setup lang="ts"> +import Sortable from "sortablejs"; +import SearchHistoryItem from "./SearchHistoryItem.vue"; +import type { optionsItem, dragItem, Props } from "../types"; +import { useEpThemeStoreHook } from "@/store/modules/epTheme"; +import { useResizeObserver, isArray, delay } from "@pureadmin/utils"; +import { ref, watch, nextTick, computed, getCurrentInstance } from "vue"; + +interface Emits { + (e: "update:value", val: string): void; + (e: "enter"): void; + (e: "collect", val: optionsItem): void; + (e: "delete", val: optionsItem): void; + (e: "drag", val: dragItem): void; +} + +const historyRef = ref(); +const innerHeight = ref(); +/** 鍒ゆ柇鏄惁鍋滄榧犳爣绉诲叆浜嬩欢澶勭悊 */ +const stopMouseEvent = ref(false); + +const emit = defineEmits<Emits>(); +const instance = getCurrentInstance()!; +const props = withDefaults(defineProps<Props>(), {}); + +const itemStyle = computed(() => { + return item => { + return { + background: + item?.path === active.value ? useEpThemeStoreHook().epThemeColor : "", + color: item.path === active.value ? "#fff" : "", + fontSize: item.path === active.value ? "16px" : "14px" + }; + }; +}); + +const titleStyle = computed(() => { + return { + color: useEpThemeStoreHook().epThemeColor, + fontWeight: 500 + }; +}); + +const active = computed({ + get() { + return props.value; + }, + set(val: string) { + emit("update:value", val); + } +}); + +watch( + () => props.value, + newValue => { + if (newValue) { + if (stopMouseEvent.value) { + delay(100).then(() => (stopMouseEvent.value = false)); + } + } + } +); + +const historyList = computed(() => { + return props.options.filter(item => item.type === "history"); +}); + +const collectList = computed(() => { + return props.options.filter(item => item.type === "collect"); +}); + +function handleCollect(item) { + emit("collect", item); +} + +function handleDelete(item) { + stopMouseEvent.value = true; + emit("delete", item); +} + +/** 榧犳爣绉诲叆 */ +async function handleMouse(item) { + if (!stopMouseEvent.value) active.value = item.path; +} + +function handleTo() { + emit("enter"); +} + +function resizeResult() { + // el-scrollbar max-height="calc(90vh - 140px)" + innerHeight.value = window.innerHeight - window.innerHeight / 10 - 140; +} + +useResizeObserver(historyRef, resizeResult); + +function handleScroll(index: number) { + const curInstance = instance?.proxy?.$refs[`historyItemRef${index}`]; + if (!curInstance) return 0; + const curRef = isArray(curInstance) + ? (curInstance[0] as ElRef) + : (curInstance as ElRef); + const scrollTop = curRef.offsetTop + 128; // 128 涓や釜history-item锛�56px+56px=112px锛夐珮搴﹀姞涓婁笅margin锛�8px+8px=16px锛� + return scrollTop > innerHeight.value ? scrollTop - innerHeight.value : 0; +} + +const handleChangeIndex = (evt): void => { + emit("drag", { oldIndex: evt.oldIndex, newIndex: evt.newIndex }); +}; + +let sortableInstance = null; + +watch( + collectList, + val => { + if (val.length > 1) { + nextTick(() => { + const wrapper: HTMLElement = + document.querySelector(".collect-container"); + if (!wrapper || sortableInstance) return; + sortableInstance = Sortable.create(wrapper, { + animation: 160, + onStart: event => { + event.item.style.cursor = "move"; + }, + onEnd: event => { + event.item.style.cursor = "pointer"; + }, + onUpdate: handleChangeIndex + }); + resizeResult(); + }); + } + }, + { deep: true, immediate: true } +); + +defineExpose({ handleScroll }); +</script> + +<template> + <div ref="historyRef" class="history"> + <template v-if="historyList.length"> + <div :style="titleStyle">鎼滅储鍘嗗彶</div> + <div + v-for="(item, index) in historyList" + :key="item.path" + :ref="'historyItemRef' + index" + class="history-item dark:bg-[#1d1d1d]" + :style="itemStyle(item)" + @click="handleTo" + @mouseenter="handleMouse(item)" + > + <SearchHistoryItem + :item="item" + @delete-item="handleDelete" + @collect-item="handleCollect" + /> + </div> + </template> + <template v-if="collectList.length"> + <div :style="titleStyle"> + {{ `鏀惰棌${collectList.length > 1 ? "锛堝彲鎷栨嫿鎺掑簭锛�" : ""}` }} + </div> + <div class="collect-container"> + <div + v-for="(item, index) in collectList" + :key="item.path" + :ref="'historyItemRef' + (index + historyList.length)" + class="history-item dark:bg-[#1d1d1d]" + :style="itemStyle(item)" + @click="handleTo" + @mouseenter="handleMouse(item)" + > + <SearchHistoryItem :item="item" @delete-item="handleDelete" /> + </div> + </div> + </template> + </div> +</template> + +<style lang="scss" scoped> +.history { + padding-bottom: 12px; + + &-item { + display: flex; + align-items: center; + height: 56px; + padding: 14px; + margin: 8px auto 10px; + cursor: pointer; + border: 0.1px solid #ccc; + border-radius: 4px; + transition: font-size 0.16s; + } +} +</style> diff --git a/src/layout/components/lay-search/components/SearchHistoryItem.vue b/src/layout/components/lay-search/components/SearchHistoryItem.vue new file mode 100644 index 0000000..b94ccde --- /dev/null +++ b/src/layout/components/lay-search/components/SearchHistoryItem.vue @@ -0,0 +1,52 @@ +<script setup lang="ts"> +import type { optionsItem } from "../types"; +import { useRenderIcon } from "@/components/ReIcon/src/hooks"; +import StarIcon from "~icons/ep/star"; +import CloseIcon from "~icons/ep/close"; + +interface Props { + item: optionsItem; +} + +interface Emits { + (e: "collectItem", val: optionsItem): void; + (e: "deleteItem", val: optionsItem): void; +} + +const emit = defineEmits<Emits>(); +withDefaults(defineProps<Props>(), {}); + +function handleCollect(item) { + emit("collectItem", item); +} + +function handleDelete(item) { + emit("deleteItem", item); +} +</script> + +<template> + <component :is="useRenderIcon(item.meta?.icon)" /> + <span class="history-item-title"> + {{ item.meta?.title }} + </span> + <IconifyIconOffline + v-show="item.type === 'history'" + :icon="StarIcon" + class="w-[18px] h-[18px] mr-2 hover:text-[#d7d5d4]" + @click.stop="handleCollect(item)" + /> + <IconifyIconOffline + :icon="CloseIcon" + class="w-[18px] h-[18px] hover:text-[#d7d5d4] cursor-pointer" + @click.stop="handleDelete(item)" + /> +</template> + +<style lang="scss" scoped> +.history-item-title { + display: flex; + flex: 1; + margin-left: 5px; +} +</style> diff --git a/src/layout/components/lay-search/components/SearchModal.vue b/src/layout/components/lay-search/components/SearchModal.vue new file mode 100644 index 0000000..af778c0 --- /dev/null +++ b/src/layout/components/lay-search/components/SearchModal.vue @@ -0,0 +1,334 @@ +<script setup lang="ts"> +import { match } from "pinyin-pro"; +import { getConfig } from "@/config"; +import { useRouter } from "vue-router"; +import SearchResult from "./SearchResult.vue"; +import SearchFooter from "./SearchFooter.vue"; +import { useNav } from "@/layout/hooks/useNav"; +import SearchHistory from "./SearchHistory.vue"; +import type { optionsItem, dragItem } from "../types"; +import { ref, computed, shallowRef, watch } from "vue"; +import { useDebounceFn, onKeyStroke } from "@vueuse/core"; +import { usePermissionStoreHook } from "@/store/modules/permission"; +import { cloneDeep, isAllEmpty, storageLocal } from "@pureadmin/utils"; +import SearchIcon from "~icons/ri/search-line"; + +interface Props { + /** 寮圭獥鏄鹃殣 */ + value: boolean; +} + +interface Emits { + (e: "update:value", val: boolean): void; +} + +const { device } = useNav(); +const emit = defineEmits<Emits>(); +const props = withDefaults(defineProps<Props>(), {}); + +const router = useRouter(); + +const HISTORY_TYPE = "history"; +const COLLECT_TYPE = "collect"; +const LOCALEHISTORYKEY = "menu-search-history"; +const LOCALECOLLECTKEY = "menu-search-collect"; + +const keyword = ref(""); +const resultRef = ref(); +const historyRef = ref(); +const scrollbarRef = ref(); +const activePath = ref(""); +const historyPath = ref(""); +const resultOptions = shallowRef([]); +const historyOptions = shallowRef([]); +const handleSearch = useDebounceFn(search, 300); +const historyNum = getConfig().MenuSearchHistory; +const inputRef = ref<HTMLInputElement | null>(null); + +/** 鑿滃崟鏍戝舰缁撴瀯 */ +const menusData = computed(() => { + return cloneDeep(usePermissionStoreHook().wholeMenus); +}); + +const show = computed({ + get() { + return props.value; + }, + set(val: boolean) { + emit("update:value", val); + } +}); + +watch( + () => props.value, + newValue => { + if (newValue) getHistory(); + } +); + +const showSearchResult = computed(() => { + return keyword.value && resultOptions.value.length > 0; +}); + +const showSearchHistory = computed(() => { + return !keyword.value && historyOptions.value.length > 0; +}); + +const showEmpty = computed(() => { + return ( + (!keyword.value && historyOptions.value.length === 0) || + (keyword.value && resultOptions.value.length === 0) + ); +}); + +function getStorageItem(key) { + return storageLocal().getItem<optionsItem[]>(key) || []; +} + +function setStorageItem(key, value) { + storageLocal().setItem(key, value); +} + +/** 灏嗚彍鍗曟爲褰㈢粨鏋勬墎骞冲寲涓轰竴缁存暟缁勶紝鐢ㄤ簬鑿滃崟鏌ヨ */ +function flatTree(arr) { + const res = []; + function deep(arr) { + arr.forEach(item => { + res.push(item); + item.children && deep(item.children); + }); + } + deep(arr); + return res; +} + +/** 鏌ヨ */ +function search() { + const flatMenusData = flatTree(menusData.value); + resultOptions.value = flatMenusData.filter(menu => + keyword.value + ? menu.meta?.title + .toLocaleLowerCase() + .includes(keyword.value.toLocaleLowerCase().trim()) || + !isAllEmpty( + match( + menu.meta?.title.toLocaleLowerCase(), + keyword.value.toLocaleLowerCase().trim() + ) + ) + : false + ); + activePath.value = + resultOptions.value?.length > 0 ? resultOptions.value[0].path : ""; +} + +function handleClose() { + show.value = false; + /** 寤舵椂澶勭悊闃叉鐢ㄦ埛鐪嬪埌鏌愪簺鎿嶄綔 */ + setTimeout(() => { + resultOptions.value = []; + historyPath.value = ""; + keyword.value = ""; + }, 200); +} + +function scrollTo(index) { + const ref = resultOptions.value.length ? resultRef.value : historyRef.value; + const scrollTop = ref.handleScroll(index); + scrollbarRef.value.setScrollTop(scrollTop); +} + +/** 鑾峰彇褰撳墠閫夐」鍜岃矾寰� */ +function getCurrentOptionsAndPath() { + const isResultOptions = resultOptions.value.length > 0; + const options = isResultOptions ? resultOptions.value : historyOptions.value; + const currentPath = isResultOptions ? activePath.value : historyPath.value; + return { options, currentPath, isResultOptions }; +} + +/** 鏇存柊璺緞骞舵粴鍔ㄥ埌鎸囧畾椤� */ +function updatePathAndScroll(newIndex, isResultOptions) { + if (isResultOptions) { + activePath.value = resultOptions.value[newIndex].path; + } else { + historyPath.value = historyOptions.value[newIndex].path; + } + scrollTo(newIndex); +} + +/** key up */ +function handleUp() { + const { options, currentPath, isResultOptions } = getCurrentOptionsAndPath(); + if (options.length === 0) return; + const index = options.findIndex(item => item.path === currentPath); + const prevIndex = (index - 1 + options.length) % options.length; + updatePathAndScroll(prevIndex, isResultOptions); +} + +/** key down */ +function handleDown() { + const { options, currentPath, isResultOptions } = getCurrentOptionsAndPath(); + if (options.length === 0) return; + const index = options.findIndex(item => item.path === currentPath); + const nextIndex = (index + 1) % options.length; + updatePathAndScroll(nextIndex, isResultOptions); +} + +/** key enter */ +function handleEnter() { + const { options, currentPath, isResultOptions } = getCurrentOptionsAndPath(); + if (options.length === 0 || currentPath === "") return; + const index = options.findIndex(item => item.path === currentPath); + if (index === -1) return; + if (isResultOptions) { + saveHistory(); + } else { + updateHistory(); + } + router.push(options[index].path); + handleClose(); +} + +/** 鍒犻櫎鍘嗗彶璁板綍 */ +function handleDelete(item) { + const key = item.type === HISTORY_TYPE ? LOCALEHISTORYKEY : LOCALECOLLECTKEY; + let list = getStorageItem(key); + list = list.filter(listItem => listItem.path !== item.path); + setStorageItem(key, list); + getHistory(); +} + +/** 鏀惰棌鍘嗗彶璁板綍 */ +function handleCollect(item) { + let searchHistoryList = getStorageItem(LOCALEHISTORYKEY); + let searchCollectList = getStorageItem(LOCALECOLLECTKEY); + searchHistoryList = searchHistoryList.filter( + historyItem => historyItem.path !== item.path + ); + setStorageItem(LOCALEHISTORYKEY, searchHistoryList); + if (!searchCollectList.some(collectItem => collectItem.path === item.path)) { + searchCollectList.unshift({ ...item, type: COLLECT_TYPE }); + setStorageItem(LOCALECOLLECTKEY, searchCollectList); + } + getHistory(); +} + +/** 瀛樺偍鎼滅储璁板綍 */ +function saveHistory() { + const { path, meta } = resultOptions.value.find( + item => item.path === activePath.value + ); + const searchHistoryList = getStorageItem(LOCALEHISTORYKEY); + const searchCollectList = getStorageItem(LOCALECOLLECTKEY); + const isCollected = searchCollectList.some(item => item.path === path); + const existingIndex = searchHistoryList.findIndex(item => item.path === path); + if (!isCollected) { + if (existingIndex !== -1) searchHistoryList.splice(existingIndex, 1); + if (searchHistoryList.length >= historyNum) searchHistoryList.pop(); + searchHistoryList.unshift({ path, meta, type: HISTORY_TYPE }); + storageLocal().setItem(LOCALEHISTORYKEY, searchHistoryList); + } +} + +/** 鏇存柊瀛樺偍鐨勬悳绱㈣褰� */ +function updateHistory() { + let searchHistoryList = getStorageItem(LOCALEHISTORYKEY); + const historyIndex = searchHistoryList.findIndex( + item => item.path === historyPath.value + ); + if (historyIndex !== -1) { + const [historyItem] = searchHistoryList.splice(historyIndex, 1); + searchHistoryList.unshift(historyItem); + setStorageItem(LOCALEHISTORYKEY, searchHistoryList); + } +} + +/** 鑾峰彇鏈湴鍘嗗彶璁板綍 */ +function getHistory() { + const searchHistoryList = getStorageItem(LOCALEHISTORYKEY); + const searchCollectList = getStorageItem(LOCALECOLLECTKEY); + historyOptions.value = [...searchHistoryList, ...searchCollectList]; + historyPath.value = historyOptions.value[0]?.path; +} + +/** 鎷栨嫿鏀瑰彉鏀惰棌椤哄簭 */ +function handleDrag(item: dragItem) { + const searchCollectList = getStorageItem(LOCALECOLLECTKEY); + const [reorderedItem] = searchCollectList.splice(item.oldIndex, 1); + searchCollectList.splice(item.newIndex, 0, reorderedItem); + storageLocal().setItem(LOCALECOLLECTKEY, searchCollectList); + historyOptions.value = [ + ...getStorageItem(LOCALEHISTORYKEY), + ...getStorageItem(LOCALECOLLECTKEY) + ]; + historyPath.value = reorderedItem.path; +} + +onKeyStroke("Enter", handleEnter); +onKeyStroke("ArrowUp", handleUp); +onKeyStroke("ArrowDown", handleDown); +</script> + +<template> + <el-dialog + v-model="show" + top="5vh" + class="pure-search-dialog" + :show-close="false" + :width="device === 'mobile' ? '80vw' : '40vw'" + :before-close="handleClose" + :style="{ + borderRadius: '6px' + }" + append-to-body + @opened="inputRef.focus()" + @closed="inputRef.blur()" + > + <el-input + ref="inputRef" + v-model="keyword" + size="large" + clearable + placeholder="鎼滅储鑿滃崟锛堟敮鎸佹嫾闊虫悳绱級" + @input="handleSearch" + > + <template #prefix> + <IconifyIconOffline + :icon="SearchIcon" + class="text-primary w-[24px] h-[24px]" + /> + </template> + </el-input> + <div class="search-content"> + <el-scrollbar ref="scrollbarRef" max-height="calc(90vh - 140px)"> + <el-empty v-if="showEmpty" description="鏆傛棤鎼滅储缁撴灉" /> + <SearchHistory + v-if="showSearchHistory" + ref="historyRef" + v-model:value="historyPath" + :options="historyOptions" + @click="handleEnter" + @delete="handleDelete" + @collect="handleCollect" + @drag="handleDrag" + /> + <SearchResult + v-if="showSearchResult" + ref="resultRef" + v-model:value="activePath" + :options="resultOptions" + @click="handleEnter" + /> + </el-scrollbar> + </div> + <template #footer> + <SearchFooter :total="resultOptions.length" /> + </template> + </el-dialog> +</template> + +<style lang="scss" scoped> +.search-content { + margin-top: 12px; +} +</style> diff --git a/src/layout/components/lay-search/components/SearchResult.vue b/src/layout/components/lay-search/components/SearchResult.vue new file mode 100644 index 0000000..1dc7841 --- /dev/null +++ b/src/layout/components/lay-search/components/SearchResult.vue @@ -0,0 +1,113 @@ +<script setup lang="ts"> +import type { Props } from "../types"; +import { useResizeObserver } from "@pureadmin/utils"; +import { useEpThemeStoreHook } from "@/store/modules/epTheme"; +import { useRenderIcon } from "@/components/ReIcon/src/hooks"; +import { ref, computed, getCurrentInstance, onMounted } from "vue"; +import EnterOutlined from "@/assets/svg/enter_outlined.svg?component"; + +interface Emits { + (e: "update:value", val: string): void; + (e: "enter"): void; +} + +const resultRef = ref(); +const innerHeight = ref(); +const emit = defineEmits<Emits>(); +const instance = getCurrentInstance()!; +const props = withDefaults(defineProps<Props>(), {}); + +const itemStyle = computed(() => { + return item => { + return { + background: + item?.path === active.value ? useEpThemeStoreHook().epThemeColor : "", + color: item.path === active.value ? "#fff" : "", + fontSize: item.path === active.value ? "16px" : "14px" + }; + }; +}); + +const active = computed({ + get() { + return props.value; + }, + set(val: string) { + emit("update:value", val); + } +}); + +/** 榧犳爣绉诲叆 */ +async function handleMouse(item) { + active.value = item.path; +} + +function handleTo() { + emit("enter"); +} + +function resizeResult() { + // el-scrollbar max-height="calc(90vh - 140px)" + innerHeight.value = window.innerHeight - window.innerHeight / 10 - 140; +} + +useResizeObserver(resultRef, resizeResult); + +function handleScroll(index: number) { + const curInstance = instance?.proxy?.$refs[`resultItemRef${index}`]; + if (!curInstance) return 0; + const curRef = curInstance[0] as ElRef; + const scrollTop = curRef.offsetTop + 128; // 128 涓や釜result-item锛�56px+56px=112px锛夐珮搴﹀姞涓婁笅margin锛�8px+8px=16px锛� + return scrollTop > innerHeight.value ? scrollTop - innerHeight.value : 0; +} + +onMounted(() => { + resizeResult(); +}); + +defineExpose({ handleScroll }); +</script> + +<template> + <div ref="resultRef" class="result"> + <div + v-for="(item, index) in options" + :key="item.path" + :ref="'resultItemRef' + index" + class="result-item dark:bg-[#1d1d1d]" + :style="itemStyle(item)" + @click="handleTo" + @mouseenter="handleMouse(item)" + > + <component :is="useRenderIcon(item.meta?.icon)" /> + <span class="result-item-title"> + {{ item.meta?.title }} + </span> + <EnterOutlined /> + </div> + </div> +</template> + +<style lang="scss" scoped> +.result { + padding-bottom: 12px; + + &-item { + display: flex; + align-items: center; + height: 56px; + padding: 14px; + margin-top: 8px; + cursor: pointer; + border: 0.1px solid #ccc; + border-radius: 4px; + transition: font-size 0.16s; + + &-title { + display: flex; + flex: 1; + margin-left: 5px; + } + } +} +</style> diff --git a/src/layout/components/lay-search/index.vue b/src/layout/components/lay-search/index.vue new file mode 100644 index 0000000..b9bf15c --- /dev/null +++ b/src/layout/components/lay-search/index.vue @@ -0,0 +1,21 @@ +<script setup lang="ts"> +import { useBoolean } from "../../hooks/useBoolean"; +import SearchModal from "./components/SearchModal.vue"; + +const { bool: show, toggle } = useBoolean(); +function handleSearch() { + toggle(); +} +</script> + +<template> + <div> + <div + class="search-container w-[40px] h-[48px] flex-c cursor-pointer navbar-bg-hover" + @click="handleSearch" + > + <IconifyIconOffline icon="ri/search-line" /> + </div> + <SearchModal v-model:value="show" /> + </div> +</template> diff --git a/src/layout/components/lay-search/types.ts b/src/layout/components/lay-search/types.ts new file mode 100644 index 0000000..a39adbd --- /dev/null +++ b/src/layout/components/lay-search/types.ts @@ -0,0 +1,20 @@ +interface optionsItem { + path: string; + type: "history" | "collect"; + meta: { + icon?: string; + title?: string; + }; +} + +interface dragItem { + oldIndex: number; + newIndex: number; +} + +interface Props { + value: string; + options: Array<optionsItem>; +} + +export type { optionsItem, dragItem, Props }; diff --git a/src/layout/components/lay-setting/index.vue b/src/layout/components/lay-setting/index.vue new file mode 100644 index 0000000..2294667 --- /dev/null +++ b/src/layout/components/lay-setting/index.vue @@ -0,0 +1,631 @@ +<script setup lang="ts"> +import { + ref, + unref, + watch, + reactive, + computed, + nextTick, + onUnmounted, + onBeforeMount +} from "vue"; +import { emitter } from "@/utils/mitt"; +import LayPanel from "../lay-panel/index.vue"; +import { useNav } from "@/layout/hooks/useNav"; +import { useAppStoreHook } from "@/store/modules/app"; +import { useMultiTagsStoreHook } from "@/store/modules/multiTags"; +import Segmented, { type OptionsType } from "@/components/ReSegmented"; +import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange"; +import { useDark, useGlobal, debounce, isNumber } from "@pureadmin/utils"; + +import Check from "~icons/ep/check"; +import LeftArrow from "~icons/ri/arrow-left-s-line?width=20&height=20"; +import RightArrow from "~icons/ri/arrow-right-s-line?width=20&height=20"; +import DayIcon from "@/assets/svg/day.svg?component"; +import DarkIcon from "@/assets/svg/dark.svg?component"; +import SystemIcon from "@/assets/svg/system.svg?component"; + +const { device } = useNav(); +const { isDark } = useDark(); +const { $storage } = useGlobal<GlobalPropertiesApi>(); + +const mixRef = ref(); +const verticalRef = ref(); +const horizontalRef = ref(); + +const { + dataTheme, + overallStyle, + layoutTheme, + themeColors, + toggleClass, + dataThemeChange, + setLayoutThemeColor +} = useDataThemeChange(); + +/* body娣诲姞layout灞炴�э紝浣滅敤浜巗rc/style/sidebar.scss */ +if (unref(layoutTheme)) { + const layout = unref(layoutTheme).layout; + const theme = unref(layoutTheme).theme; + document.documentElement.setAttribute("data-theme", theme); + setLayoutModel(layout); +} + +/** 榛樿鐏靛姩妯″紡 */ +const markValue = ref($storage.configure?.showModel ?? "smart"); + +const logoVal = ref($storage.configure?.showLogo ?? true); + +const settings = reactive({ + greyVal: $storage.configure.grey, + weakVal: $storage.configure.weak, + tabsVal: $storage.configure.hideTabs, + showLogo: $storage.configure.showLogo, + showModel: $storage.configure.showModel, + hideFooter: $storage.configure.hideFooter, + multiTagsCache: $storage.configure.multiTagsCache, + stretch: $storage.configure.stretch +}); + +const getThemeColorStyle = computed(() => { + return color => { + return { background: color }; + }; +}); + +/** 褰撶綉椤垫暣浣撲负鏆楄壊椋庢牸鏃朵笉鏄剧ず浜櫧鑹蹭富棰橀厤鑹插垏鎹㈤�夐」 */ +const showThemeColors = computed(() => { + return themeColor => { + return themeColor === "light" && isDark.value ? false : true; + }; +}); + +function storageConfigureChange<T>(key: string, val: T): void { + const storageConfigure = $storage.configure; + storageConfigure[key] = val; + $storage.configure = storageConfigure; +} + +/** 鐏拌壊妯″紡璁剧疆 */ +const greyChange = (value): void => { + const htmlEl = document.querySelector("html"); + toggleClass(settings.greyVal, "html-grey", htmlEl); + storageConfigureChange("grey", value); +}; + +/** 鑹插急妯″紡璁剧疆 */ +const weekChange = (value): void => { + const htmlEl = document.querySelector("html"); + toggleClass(settings.weakVal, "html-weakness", htmlEl); + storageConfigureChange("weak", value); +}; + +/** 闅愯棌鏍囩椤佃缃� */ +const tagsChange = () => { + const showVal = settings.tabsVal; + storageConfigureChange("hideTabs", showVal); + emitter.emit("tagViewsChange", showVal as unknown as string); +}; + +/** 闅愯棌椤佃剼璁剧疆 */ +const hideFooterChange = () => { + const hideFooter = settings.hideFooter; + storageConfigureChange("hideFooter", hideFooter); +}; + +/** 鏍囩椤垫寔涔呭寲璁剧疆 */ +const multiTagsCacheChange = () => { + const multiTagsCache = settings.multiTagsCache; + storageConfigureChange("multiTagsCache", multiTagsCache); + useMultiTagsStoreHook().multiTagsCacheChange(multiTagsCache); +}; + +function onChange({ option }) { + const { value } = option; + markValue.value = value; + storageConfigureChange("showModel", value); + emitter.emit("tagViewsShowModel", value); +} + +/** 渚ц竟鏍廘ogo */ +function logoChange() { + unref(logoVal) + ? storageConfigureChange("showLogo", true) + : storageConfigureChange("showLogo", false); + emitter.emit("logoChange", unref(logoVal)); +} + +function setFalse(Doms): any { + Doms.forEach(v => { + toggleClass(false, "is-select", unref(v)); + }); +} + +/** 椤靛 */ +const stretchTypeOptions = computed<Array<OptionsType>>(() => { + return [ + { + label: "鍥哄畾", + tip: "绱у噾椤甸潰锛岃交鏉炬壘鍒版墍闇�淇℃伅", + value: "fixed" + }, + { + label: "鑷畾涔�", + tip: "鏈�灏�1280銆佹渶澶�1600", + value: "custom" + } + ]; +}); + +const setStretch = value => { + settings.stretch = value; + storageConfigureChange("stretch", value); +}; + +const stretchTypeChange = ({ option }) => { + const { value } = option; + value === "custom" ? setStretch(1440) : setStretch(false); +}; + +/** 涓婚鑹� 婵�娲婚�夋嫨椤� */ +const getThemeColor = computed(() => { + return current => { + if ( + current === layoutTheme.value.theme && + layoutTheme.value.theme !== "light" + ) { + return "#fff"; + } else if ( + current === layoutTheme.value.theme && + layoutTheme.value.theme === "light" + ) { + return "#1d2b45"; + } else { + return "transparent"; + } + }; +}); + +const pClass = computed(() => { + return ["mb-[12px]!", "font-medium", "text-sm", "dark:text-white"]; +}); + +const themeOptions = computed<Array<OptionsType>>(() => { + return [ + { + label: "娴呰壊", + icon: DayIcon, + theme: "light", + tip: "娓呮柊鍚埅锛岀偣浜垝閫傜殑宸ヤ綔鐣岄潰", + iconAttrs: { fill: isDark.value ? "#fff" : "#000" } + }, + { + label: "娣辫壊", + icon: DarkIcon, + theme: "dark", + tip: "鏈堝厜搴忔洸锛屾矇閱変簬澶滅殑闈欒哀闆呰嚧", + iconAttrs: { fill: isDark.value ? "#fff" : "#000" } + }, + { + label: "鑷姩", + icon: SystemIcon, + theme: "system", + tip: "鍚屾鏃跺厜锛岀晫闈㈤殢鏅ㄦ槒鑷劧鍛煎簲", + iconAttrs: { fill: isDark.value ? "#fff" : "#000" } + } + ]; +}); + +const markOptions = computed<Array<OptionsType>>(() => { + return [ + { + label: "鐏靛姩", + tip: "鐏靛姩鏍囩锛屾坊瓒g敓杈�", + value: "smart" + }, + { + label: "鍗$墖", + tip: "鍗$墖鏍囩锛岄珮鏁堟祻瑙�", + value: "card" + }, + { + label: "璋锋瓕", + tip: "璋锋瓕椋庢牸锛岀粡鍏哥編瑙�", + value: "chrome" + } + ]; +}); + +/** 璁剧疆瀵艰埅妯″紡 */ +function setLayoutModel(layout: string) { + layoutTheme.value.layout = layout; + window.document.body.setAttribute("layout", layout); + $storage.layout = { + layout, + theme: layoutTheme.value.theme, + darkMode: $storage.layout?.darkMode, + sidebarStatus: $storage.layout?.sidebarStatus, + epThemeColor: $storage.layout?.epThemeColor, + themeColor: $storage.layout?.themeColor, + overallStyle: $storage.layout?.overallStyle + }; + useAppStoreHook().setLayout(layout); +} + +watch($storage, ({ layout }) => { + switch (layout["layout"]) { + case "vertical": + toggleClass(true, "is-select", unref(verticalRef)); + debounce(setFalse([horizontalRef]), 50); + debounce(setFalse([mixRef]), 50); + break; + case "horizontal": + toggleClass(true, "is-select", unref(horizontalRef)); + debounce(setFalse([verticalRef]), 50); + debounce(setFalse([mixRef]), 50); + break; + case "mix": + toggleClass(true, "is-select", unref(mixRef)); + debounce(setFalse([verticalRef]), 50); + debounce(setFalse([horizontalRef]), 50); + break; + } +}); + +const mediaQueryList = window.matchMedia("(prefers-color-scheme: dark)"); + +/** 鏍规嵁鎿嶄綔绯荤粺涓婚璁剧疆骞冲彴鏁翠綋椋庢牸 */ +function updateTheme() { + if (overallStyle.value !== "system") return; + if (mediaQueryList.matches) { + dataTheme.value = true; + } else { + dataTheme.value = false; + } + dataThemeChange(overallStyle.value); +} + +function removeMatchMedia() { + mediaQueryList.removeEventListener("change", updateTheme); +} + +/** 鐩戝惉鎿嶄綔绯荤粺涓婚鏀瑰彉 */ +function watchSystemThemeChange() { + updateTheme(); + removeMatchMedia(); + mediaQueryList.addEventListener("change", updateTheme); +} + +onBeforeMount(() => { + /* 鍒濆鍖栫郴缁熼厤缃� */ + nextTick(() => { + watchSystemThemeChange(); + settings.greyVal && + document.querySelector("html")?.classList.add("html-grey"); + settings.weakVal && + document.querySelector("html")?.classList.add("html-weakness"); + settings.tabsVal && tagsChange(); + settings.hideFooter && hideFooterChange(); + }); +}); + +onUnmounted(() => removeMatchMedia); +</script> + +<template> + <LayPanel> + <div class="p-5"> + <p :class="pClass">鏁翠綋椋庢牸</p> + <Segmented + resize + class="select-none" + :modelValue="overallStyle === 'system' ? 2 : dataTheme ? 1 : 0" + :options="themeOptions" + @change=" + theme => { + theme.index === 1 && theme.index !== 2 + ? (dataTheme = true) + : (dataTheme = false); + overallStyle = theme.option.theme; + dataThemeChange(theme.option.theme); + theme.index === 2 && watchSystemThemeChange(); + } + " + /> + + <p :class="['mt-5!', pClass]">涓婚鑹�</p> + <ul class="theme-color"> + <li + v-for="(item, index) in themeColors" + v-show="showThemeColors(item.themeColor)" + :key="index" + :style="getThemeColorStyle(item.color)" + @click="setLayoutThemeColor(item.themeColor)" + > + <el-icon + style="margin: 0.1em 0.1em 0 0" + :size="17" + :color="getThemeColor(item.themeColor)" + > + <IconifyIconOffline :icon="Check" /> + </el-icon> + </li> + </ul> + + <p :class="['mt-5!', pClass]">瀵艰埅妯″紡</p> + <ul class="pure-theme"> + <li + ref="verticalRef" + v-tippy="{ + content: '宸︿晶鑿滃崟锛屼翰鍒囩啛鎮�', + zIndex: 41000 + }" + :class="layoutTheme.layout === 'vertical' ? 'is-select' : ''" + @click="setLayoutModel('vertical')" + > + <div /> + <div /> + </li> + <li + v-if="device !== 'mobile'" + ref="horizontalRef" + v-tippy="{ + content: '椤堕儴鑿滃崟锛岀畝娲佹瑙�', + zIndex: 41000 + }" + :class="layoutTheme.layout === 'horizontal' ? 'is-select' : ''" + @click="setLayoutModel('horizontal')" + > + <div /> + <div /> + </li> + <li + v-if="device !== 'mobile'" + ref="mixRef" + v-tippy="{ + content: '娣峰悎鑿滃崟锛岀伒娲诲鍙�', + zIndex: 41000 + }" + :class="layoutTheme.layout === 'mix' ? 'is-select' : ''" + @click="setLayoutModel('mix')" + > + <div /> + <div /> + </li> + </ul> + + <span v-if="useAppStoreHook().getViewportWidth > 1280"> + <p :class="['mt-5!', pClass]">椤靛</p> + <Segmented + resize + class="mb-2 select-none" + :modelValue="isNumber(settings.stretch) ? 1 : 0" + :options="stretchTypeOptions" + @change="stretchTypeChange" + /> + <el-input-number + v-if="isNumber(settings.stretch)" + v-model="settings.stretch as number" + :min="1280" + :max="1600" + controls-position="right" + @change="value => setStretch(value)" + /> + <button + v-else + v-ripple="{ class: 'text-gray-300' }" + class="bg-transparent flex-c w-full h-20 rounded-md border border-[var(--pure-border-color)]" + @click="setStretch(!settings.stretch)" + > + <div + class="flex-bc transition-all duration-300" + :class="[settings.stretch ? 'w-[24%]' : 'w-[50%]']" + style="color: var(--el-color-primary)" + > + <IconifyIconOffline + :icon="settings.stretch ? RightArrow : LeftArrow" + /> + <div + class="grow border-0 border-b border-dashed" + style="border-color: var(--el-color-primary)" + /> + <IconifyIconOffline + :icon="settings.stretch ? LeftArrow : RightArrow" + /> + </div> + </button> + </span> + + <p :class="['mt-4!', pClass]">椤电椋庢牸</p> + <Segmented + resize + class="select-none" + :modelValue="markValue === 'smart' ? 0 : markValue === 'card' ? 1 : 2" + :options="markOptions" + @change="onChange" + /> + + <p class="mt-5! font-medium text-sm dark:text-white">鐣岄潰鏄剧ず</p> + <ul class="setting"> + <li> + <span class="dark:text-white">鐏拌壊妯″紡</span> + <el-switch + v-model="settings.greyVal" + inline-prompt + active-text="寮�" + inactive-text="鍏�" + @change="greyChange" + /> + </li> + <li> + <span class="dark:text-white">鑹插急妯″紡</span> + <el-switch + v-model="settings.weakVal" + inline-prompt + active-text="寮�" + inactive-text="鍏�" + @change="weekChange" + /> + </li> + <li> + <span class="dark:text-white">闅愯棌鏍囩椤�</span> + <el-switch + v-model="settings.tabsVal" + inline-prompt + active-text="寮�" + inactive-text="鍏�" + @change="tagsChange" + /> + </li> + <li> + <span class="dark:text-white">闅愯棌椤佃剼</span> + <el-switch + v-model="settings.hideFooter" + inline-prompt + active-text="寮�" + inactive-text="鍏�" + @change="hideFooterChange" + /> + </li> + <li> + <span class="dark:text-white">Logo</span> + <el-switch + v-model="logoVal" + inline-prompt + :active-value="true" + :inactive-value="false" + active-text="寮�" + inactive-text="鍏�" + @change="logoChange" + /> + </li> + <li> + <span class="dark:text-white">椤电鎸佷箙鍖�</span> + <el-switch + v-model="settings.multiTagsCache" + inline-prompt + active-text="寮�" + inactive-text="鍏�" + @change="multiTagsCacheChange" + /> + </li> + </ul> + </div> + </LayPanel> +</template> + +<style lang="scss" scoped> +:deep(.el-divider__text) { + font-size: 16px; + font-weight: 700; +} + +:deep(.el-switch__core) { + --el-switch-off-color: var(--pure-switch-off-color); + + min-width: 36px; + height: 18px; +} + +:deep(.el-switch__core .el-switch__action) { + height: 14px; +} + +.theme-color { + height: 20px; + + li { + float: left; + height: 20px; + margin-right: 8px; + cursor: pointer; + border-radius: 4px; + + &:nth-child(1) { + border: 1px solid #ddd; + } + } +} + +.pure-theme { + display: flex; + gap: 12px; + + li { + position: relative; + width: 46px; + height: 36px; + overflow: hidden; + cursor: pointer; + background: #f0f2f5; + border-radius: 4px; + box-shadow: 0 1px 2.5px 0 rgb(0 0 0 / 18%); + + &:nth-child(1) { + div { + &:nth-child(1) { + width: 30%; + height: 100%; + background: #1b2a47; + } + + &:nth-child(2) { + position: absolute; + top: 0; + right: 0; + width: 70%; + height: 30%; + background: #fff; + box-shadow: 0 0 1px #888; + } + } + } + + &:nth-child(2) { + div { + &:nth-child(1) { + width: 100%; + height: 30%; + background: #1b2a47; + box-shadow: 0 0 1px #888; + } + } + } + + &:nth-child(3) { + div { + &:nth-child(1) { + width: 100%; + height: 30%; + background: #1b2a47; + box-shadow: 0 0 1px #888; + } + + &:nth-child(2) { + position: absolute; + bottom: 0; + left: 0; + width: 30%; + height: 70%; + background: #fff; + box-shadow: 0 0 1px #888; + } + } + } + } +} + +.is-select { + border: 2px solid var(--el-color-primary); +} + +.setting { + li { + display: flex; + align-items: center; + justify-content: space-between; + padding: 3px 0; + font-size: 14px; + } +} +</style> diff --git a/src/layout/components/lay-sidebar/NavHorizontal.vue b/src/layout/components/lay-sidebar/NavHorizontal.vue new file mode 100644 index 0000000..6e8a668 --- /dev/null +++ b/src/layout/components/lay-sidebar/NavHorizontal.vue @@ -0,0 +1,123 @@ +<script setup lang="ts"> +import { emitter } from "@/utils/mitt"; +import { useNav } from "@/layout/hooks/useNav"; +import LaySearch from "../lay-search/index.vue"; +import LayNotice from "../lay-notice/index.vue"; +import { responsiveStorageNameSpace } from "@/config"; +import { ref, nextTick, computed, onMounted } from "vue"; +import { storageLocal, isAllEmpty } from "@pureadmin/utils"; +import { usePermissionStoreHook } from "@/store/modules/permission"; +import LaySidebarItem from "../lay-sidebar/components/SidebarItem.vue"; +import LaySidebarFullScreen from "../lay-sidebar/components/SidebarFullScreen.vue"; + +import LogoutCircleRLine from "~icons/ri/logout-circle-r-line"; +import Setting from "~icons/ri/settings-3-line"; + +const menuRef = ref(); +const showLogo = ref( + storageLocal().getItem<StorageConfigs>( + `${responsiveStorageNameSpace()}configure` + )?.showLogo ?? true +); + +const { + route, + title, + logout, + onPanel, + getLogo, + username, + userAvatar, + backTopMenu, + avatarsStyle +} = useNav(); + +const defaultActive = computed(() => + !isAllEmpty(route.meta?.activePath) ? route.meta.activePath : route.path +); + +nextTick(() => { + menuRef.value?.handleResize(); +}); + +onMounted(() => { + emitter.on("logoChange", key => { + showLogo.value = key; + }); +}); +</script> + +<template> + <div + v-loading="usePermissionStoreHook().wholeMenus.length === 0" + class="horizontal-header" + > + <div v-if="showLogo" class="horizontal-header-left" @click="backTopMenu"> + <img :src="getLogo()" alt="logo" /> + <span>{{ title }}</span> + </div> + <el-menu + ref="menuRef" + mode="horizontal" + popper-class="pure-scrollbar" + class="horizontal-header-menu" + :default-active="defaultActive" + > + <LaySidebarItem + v-for="route in usePermissionStoreHook().wholeMenus" + :key="route.path" + :item="route" + :base-path="route.path" + /> + </el-menu> + <div class="horizontal-header-right"> + <!-- 鑿滃崟鎼滅储 --> + <LaySearch id="header-search" /> + <!-- 鍏ㄥ睆 --> + <LaySidebarFullScreen id="full-screen" /> + <!-- 娑堟伅閫氱煡 --> + <LayNotice id="header-notice" /> + <!-- 閫�鍑虹櫥褰� --> + <el-dropdown trigger="click"> + <span class="el-dropdown-link navbar-bg-hover"> + <img :src="userAvatar" :style="avatarsStyle" /> + <p v-if="username" class="dark:text-white">{{ username }}</p> + </span> + <template #dropdown> + <el-dropdown-menu class="logout"> + <el-dropdown-item @click="logout"> + <IconifyIconOffline + :icon="LogoutCircleRLine" + style="margin: 5px" + /> + 閫�鍑虹郴缁� + </el-dropdown-item> + </el-dropdown-menu> + </template> + </el-dropdown> + <span + class="set-icon navbar-bg-hover" + title="鎵撳紑绯荤粺閰嶇疆" + @click="onPanel" + > + <IconifyIconOffline :icon="Setting" /> + </span> + </div> + </div> +</template> + +<style lang="scss" scoped> +:deep(.el-loading-mask) { + opacity: 0.45; +} + +.logout { + width: 120px; + + ::v-deep(.el-dropdown-menu__item) { + display: inline-flex; + flex-wrap: wrap; + min-width: 100%; + } +} +</style> diff --git a/src/layout/components/lay-sidebar/NavMix.vue b/src/layout/components/lay-sidebar/NavMix.vue new file mode 100644 index 0000000..32b621f --- /dev/null +++ b/src/layout/components/lay-sidebar/NavMix.vue @@ -0,0 +1,143 @@ +<script setup lang="ts"> +import { isAllEmpty } from "@pureadmin/utils"; +import { useNav } from "@/layout/hooks/useNav"; +import LaySearch from "../lay-search/index.vue"; +import LayNotice from "../lay-notice/index.vue"; +import { ref, toRaw, watch, onMounted, nextTick } from "vue"; +import { useRenderIcon } from "@/components/ReIcon/src/hooks"; +import { getParentPaths, findRouteByPath } from "@/router/utils"; +import { usePermissionStoreHook } from "@/store/modules/permission"; +import LaySidebarExtraIcon from "../lay-sidebar/components/SidebarExtraIcon.vue"; +import LaySidebarFullScreen from "../lay-sidebar/components/SidebarFullScreen.vue"; + +import LogoutCircleRLine from "~icons/ri/logout-circle-r-line"; +import Setting from "~icons/ri/settings-3-line"; + +const menuRef = ref(); +const defaultActive = ref(null); + +const { + route, + device, + logout, + onPanel, + resolvePath, + username, + userAvatar, + getDivStyle, + avatarsStyle +} = useNav(); + +function getDefaultActive(routePath) { + const wholeMenus = usePermissionStoreHook().wholeMenus; + /** 褰撳墠璺敱鐨勭埗绾ц矾寰� */ + const parentRoutes = getParentPaths(routePath, wholeMenus)[0]; + defaultActive.value = !isAllEmpty(route.meta?.activePath) + ? route.meta.activePath + : findRouteByPath(parentRoutes, wholeMenus)?.children[0]?.path; +} + +onMounted(() => { + getDefaultActive(route.path); +}); + +nextTick(() => { + menuRef.value?.handleResize(); +}); + +watch( + () => [route.path, usePermissionStoreHook().wholeMenus], + () => { + getDefaultActive(route.path); + } +); +</script> + +<template> + <div + v-if="device !== 'mobile'" + v-loading="usePermissionStoreHook().wholeMenus.length === 0" + class="horizontal-header" + > + <el-menu + ref="menuRef" + router + mode="horizontal" + popper-class="pure-scrollbar" + class="horizontal-header-menu" + :default-active="defaultActive" + > + <el-menu-item + v-for="route in usePermissionStoreHook().wholeMenus" + :key="route.path" + :index="resolvePath(route) || route.redirect" + > + <template #title> + <div + v-if="toRaw(route.meta.icon)" + :class="['sub-menu-icon', route.meta.icon]" + > + <component + :is="useRenderIcon(route.meta && toRaw(route.meta.icon))" + /> + </div> + <div :style="getDivStyle"> + <span class="select-none"> + {{ route.meta.title }} + </span> + <LaySidebarExtraIcon :extraIcon="route.meta.extraIcon" /> + </div> + </template> + </el-menu-item> + </el-menu> + <div class="horizontal-header-right"> + <!-- 鑿滃崟鎼滅储 --> + <LaySearch id="header-search" /> + <!-- 鍏ㄥ睆 --> + <LaySidebarFullScreen id="full-screen" /> + <!-- 娑堟伅閫氱煡 --> + <LayNotice id="header-notice" /> + <!-- 閫�鍑虹櫥褰� --> + <el-dropdown trigger="click"> + <span class="el-dropdown-link navbar-bg-hover select-none"> + <img :src="userAvatar" :style="avatarsStyle" /> + <p v-if="username" class="dark:text-white">{{ username }}</p> + </span> + <template #dropdown> + <el-dropdown-menu class="logout"> + <el-dropdown-item @click="logout"> + <IconifyIconOffline + :icon="LogoutCircleRLine" + style="margin: 5px" + /> + 閫�鍑虹郴缁� + </el-dropdown-item> + </el-dropdown-menu> + </template> + </el-dropdown> + <span + class="set-icon navbar-bg-hover" + title="鎵撳紑绯荤粺閰嶇疆" + @click="onPanel" + > + <IconifyIconOffline :icon="Setting" /> + </span> + </div> + </div> +</template> + +<style lang="scss" scoped> +:deep(.el-loading-mask) { + opacity: 0.45; +} + +.logout { + width: 120px; + + ::v-deep(.el-dropdown-menu__item) { + display: inline-flex; + flex-wrap: wrap; + min-width: 100%; + } +} +</style> diff --git a/src/layout/components/lay-sidebar/NavVertical.vue b/src/layout/components/lay-sidebar/NavVertical.vue new file mode 100644 index 0000000..0e9fa12 --- /dev/null +++ b/src/layout/components/lay-sidebar/NavVertical.vue @@ -0,0 +1,137 @@ +<script setup lang="ts"> +import { useRoute } from "vue-router"; +import { emitter } from "@/utils/mitt"; +import { useNav } from "@/layout/hooks/useNav"; +import { responsiveStorageNameSpace } from "@/config"; +import { storageLocal, isAllEmpty } from "@pureadmin/utils"; +import { findRouteByPath, getParentPaths } from "@/router/utils"; +import { usePermissionStoreHook } from "@/store/modules/permission"; +import { ref, computed, watch, onMounted, onBeforeUnmount } from "vue"; +import LaySidebarLogo from "../lay-sidebar/components/SidebarLogo.vue"; +import LaySidebarItem from "../lay-sidebar/components/SidebarItem.vue"; +import LaySidebarLeftCollapse from "../lay-sidebar/components/SidebarLeftCollapse.vue"; +import LaySidebarCenterCollapse from "../lay-sidebar/components/SidebarCenterCollapse.vue"; + +const route = useRoute(); +const isShow = ref(false); +const showLogo = ref( + storageLocal().getItem<StorageConfigs>( + `${responsiveStorageNameSpace()}configure` + )?.showLogo ?? true +); + +const { + device, + pureApp, + isCollapse, + tooltipEffect, + menuSelect, + toggleSideBar +} = useNav(); + +const subMenuData = ref([]); + +const menuData = computed(() => { + return pureApp.layout === "mix" && device.value !== "mobile" + ? subMenuData.value + : usePermissionStoreHook().wholeMenus; +}); + +const loading = computed(() => + pureApp.layout === "mix" ? false : menuData.value.length === 0 ? true : false +); + +const defaultActive = computed(() => + !isAllEmpty(route.meta?.activePath) ? route.meta.activePath : route.path +); + +function getSubMenuData() { + let path = ""; + path = defaultActive.value; + subMenuData.value = []; + // path鐨勪笂绾ц矾鐢辩粍鎴愮殑鏁扮粍 + const parentPathArr = getParentPaths( + path, + usePermissionStoreHook().wholeMenus + ); + // 褰撳墠璺敱鐨勭埗绾ц矾鐢变俊鎭� + const parenetRoute = findRouteByPath( + parentPathArr[0] || path, + usePermissionStoreHook().wholeMenus + ); + if (!parenetRoute?.children) return; + subMenuData.value = parenetRoute?.children; +} + +watch( + () => [route.path, usePermissionStoreHook().wholeMenus], + () => { + if (route.path.includes("/redirect")) return; + getSubMenuData(); + menuSelect(route.path); + } +); + +onMounted(() => { + getSubMenuData(); + + emitter.on("logoChange", key => { + showLogo.value = key; + }); +}); + +onBeforeUnmount(() => { + // 瑙g粦`logoChange`鍏叡浜嬩欢锛岄槻姝㈠娆¤Е鍙� + emitter.off("logoChange"); +}); +</script> + +<template> + <div + v-loading="loading" + :class="['sidebar-container', showLogo ? 'has-logo' : 'no-logo']" + @mouseenter.prevent="isShow = true" + @mouseleave.prevent="isShow = false" + > + <LaySidebarLogo v-if="showLogo" :collapse="isCollapse" /> + <el-scrollbar + wrap-class="scrollbar-wrapper" + :class="[device === 'mobile' ? 'mobile' : 'pc']" + > + <el-menu + unique-opened + mode="vertical" + popper-class="pure-scrollbar" + class="outer-most select-none" + :collapse="isCollapse" + :collapse-transition="false" + :popper-effect="tooltipEffect" + :default-active="defaultActive" + > + <LaySidebarItem + v-for="routes in menuData" + :key="routes.path" + :item="routes" + :base-path="routes.path" + class="outer-most select-none" + /> + </el-menu> + </el-scrollbar> + <LaySidebarCenterCollapse + v-if="device !== 'mobile' && (isShow || isCollapse)" + :is-active="pureApp.sidebar.opened" + @toggleClick="toggleSideBar" + /> + <LaySidebarLeftCollapse + v-if="device !== 'mobile'" + :is-active="pureApp.sidebar.opened" + @toggleClick="toggleSideBar" + /> + </div> +</template> + +<style scoped> +:deep(.el-loading-mask) { + opacity: 0.45; +} +</style> diff --git a/src/layout/components/lay-sidebar/components/SidebarBreadCrumb.vue b/src/layout/components/lay-sidebar/components/SidebarBreadCrumb.vue new file mode 100644 index 0000000..c73d5b9 --- /dev/null +++ b/src/layout/components/lay-sidebar/components/SidebarBreadCrumb.vue @@ -0,0 +1,120 @@ +<script setup lang="ts"> +import { isEqual } from "@pureadmin/utils"; +import { useRoute, useRouter } from "vue-router"; +import { ref, watch, onMounted, toRaw } from "vue"; +import { getParentPaths, findRouteByPath } from "@/router/utils"; +import { useMultiTagsStoreHook } from "@/store/modules/multiTags"; + +const route = useRoute(); +const levelList = ref([]); +const router = useRouter(); +const routes: any = router.options.routes; +const multiTags: any = useMultiTagsStoreHook().multiTags; + +const getBreadcrumb = (): void => { + // 褰撳墠璺敱淇℃伅 + let currentRoute; + + if (Object.keys(route.query).length > 0) { + multiTags.forEach(item => { + if (isEqual(route.query, item?.query)) { + currentRoute = toRaw(item); + } + }); + } else if (Object.keys(route.params).length > 0) { + multiTags.forEach(item => { + if (isEqual(route.params, item?.params)) { + currentRoute = toRaw(item); + } + }); + } else { + currentRoute = findRouteByPath(router.currentRoute.value.path, routes); + } + + // 褰撳墠璺敱鐨勭埗绾ц矾寰勭粍鎴愮殑鏁扮粍 + const parentRoutes = getParentPaths( + router.currentRoute.value.name as string, + routes, + "name" + ); + // 瀛樻斁缁勬垚闈㈠寘灞戠殑鏁扮粍 + const matched = []; + + // 鑾峰彇姣忎釜鐖剁骇璺緞瀵瑰簲鐨勮矾鐢变俊鎭� + parentRoutes.forEach(path => { + if (path !== "/") matched.push(findRouteByPath(path, routes)); + }); + + matched.push(currentRoute); + + matched.forEach((item, index) => { + if (currentRoute?.query || currentRoute?.params) return; + if (item?.children) { + item.children.forEach(v => { + if (v?.meta?.title === item?.meta?.title) { + matched.splice(index, 1); + } + }); + } + }); + + levelList.value = matched.filter( + item => item?.meta && item?.meta.title !== false + ); +}; + +const handleLink = item => { + const { redirect, name, path } = item; + if (redirect) { + router.push(redirect as any); + } else { + if (name) { + if (item.query) { + router.push({ + name, + query: item.query + }); + } else if (item.params) { + router.push({ + name, + params: item.params + }); + } else { + router.push({ name }); + } + } else { + router.push({ path }); + } + } +}; + +onMounted(() => { + getBreadcrumb(); +}); + +watch( + () => route.path, + () => { + getBreadcrumb(); + }, + { + deep: true + } +); +</script> + +<template> + <el-breadcrumb class="leading-[50px]! select-none" separator="/"> + <transition-group name="breadcrumb"> + <el-breadcrumb-item + v-for="item in levelList" + :key="item.path" + class="inline! items-stretch!" + > + <a @click.prevent="handleLink(item)"> + {{ item.meta.title }} + </a> + </el-breadcrumb-item> + </transition-group> + </el-breadcrumb> +</template> diff --git a/src/layout/components/lay-sidebar/components/SidebarCenterCollapse.vue b/src/layout/components/lay-sidebar/components/SidebarCenterCollapse.vue new file mode 100644 index 0000000..945a37a --- /dev/null +++ b/src/layout/components/lay-sidebar/components/SidebarCenterCollapse.vue @@ -0,0 +1,70 @@ +<script setup lang="ts"> +import { computed } from "vue"; +import { useGlobal } from "@pureadmin/utils"; +import { useNav } from "@/layout/hooks/useNav"; + +import ArrowLeft from "~icons/ri/arrow-left-double-fill"; + +interface Props { + isActive?: boolean; +} + +withDefaults(defineProps<Props>(), { + isActive: false +}); + +const { tooltipEffect } = useNav(); + +const iconClass = computed(() => { + return ["w-[16px]", "h-[16px]"]; +}); + +const { $storage } = useGlobal<GlobalPropertiesApi>(); +const themeColor = computed(() => $storage.layout?.themeColor); + +const emit = defineEmits<{ + (e: "toggleClick"): void; +}>(); + +const toggleClick = () => { + emit("toggleClick"); +}; +</script> + +<template> + <div + v-tippy="{ + content: isActive ? '鐐瑰嚮鎶樺彔' : '鐐瑰嚮灞曞紑', + theme: tooltipEffect, + hideOnClick: 'toggle', + placement: 'right' + }" + class="center-collapse" + @click="toggleClick" + > + <IconifyIconOffline + :icon="ArrowLeft" + :class="[iconClass, themeColor === 'light' ? '' : 'text-primary']" + :style="{ transform: isActive ? 'none' : 'rotateY(180deg)' }" + /> + </div> +</template> + +<style lang="scss" scoped> +.center-collapse { + position: absolute; + top: 50%; + right: 2px; + z-index: 1002; + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 34px; + cursor: pointer; + background: var(--el-bg-color); + border: 1px solid var(--pure-border-color); + border-radius: 4px; + transform: translate(12px, -50%); +} +</style> diff --git a/src/layout/components/lay-sidebar/components/SidebarExtraIcon.vue b/src/layout/components/lay-sidebar/components/SidebarExtraIcon.vue new file mode 100644 index 0000000..7cad16e --- /dev/null +++ b/src/layout/components/lay-sidebar/components/SidebarExtraIcon.vue @@ -0,0 +1,20 @@ +<script setup lang="ts"> +import { toRaw } from "vue"; +import { useRenderIcon } from "@/components/ReIcon/src/hooks"; + +defineProps({ + extraIcon: { + type: String, + default: "" + } +}); +</script> + +<template> + <div v-if="extraIcon" class="flex justify-center items-center"> + <component + :is="useRenderIcon(toRaw(extraIcon))" + class="w-[30px] h-[30px]" + /> + </div> +</template> diff --git a/src/layout/components/lay-sidebar/components/SidebarFullScreen.vue b/src/layout/components/lay-sidebar/components/SidebarFullScreen.vue new file mode 100644 index 0000000..4d38bd0 --- /dev/null +++ b/src/layout/components/lay-sidebar/components/SidebarFullScreen.vue @@ -0,0 +1,30 @@ +<script setup lang="ts"> +import { ref, watch } from "vue"; +import { useNav } from "@/layout/hooks/useNav"; + +const screenIcon = ref(); +const { toggle, isFullscreen, Fullscreen, ExitFullscreen } = useNav(); + +isFullscreen.value = !!( + document.fullscreenElement || + document.webkitFullscreenElement || + document.mozFullScreenElement || + document.msFullscreenElement +); + +watch( + isFullscreen, + full => { + screenIcon.value = full ? ExitFullscreen : Fullscreen; + }, + { + immediate: true + } +); +</script> + +<template> + <span class="fullscreen-icon navbar-bg-hover" @click="toggle"> + <IconifyIconOffline :icon="screenIcon" /> + </span> +</template> diff --git a/src/layout/components/lay-sidebar/components/SidebarItem.vue b/src/layout/components/lay-sidebar/components/SidebarItem.vue new file mode 100644 index 0000000..fccd130 --- /dev/null +++ b/src/layout/components/lay-sidebar/components/SidebarItem.vue @@ -0,0 +1,228 @@ +<script setup lang="ts"> +import { getConfig } from "@/config"; +import { posix } from "path-browserify"; +import { menuType } from "@/layout/types"; +import { ReText } from "@/components/ReText"; +import { useNav } from "@/layout/hooks/useNav"; +import SidebarLinkItem from "./SidebarLinkItem.vue"; +import SidebarExtraIcon from "./SidebarExtraIcon.vue"; +import { useRenderIcon } from "@/components/ReIcon/src/hooks"; +import { + type PropType, + type CSSProperties, + ref, + toRaw, + computed, + useAttrs +} from "vue"; + +import ArrowUp from "~icons/ep/arrow-up-bold"; +import EpArrowDown from "~icons/ep/arrow-down-bold"; +import ArrowLeft from "~icons/ep/arrow-left-bold"; +import ArrowRight from "~icons/ep/arrow-right-bold"; + +const attrs = useAttrs(); +const { layout, isCollapse, tooltipEffect, getDivStyle } = useNav(); + +const props = defineProps({ + item: { + type: Object as PropType<menuType> + }, + isNest: { + type: Boolean, + default: false + }, + basePath: { + type: String, + default: "" + } +}); + +const getNoDropdownStyle = computed((): CSSProperties => { + return { + width: "100%", + display: "flex", + alignItems: "center" + }; +}); + +const getSubMenuIconStyle = computed((): CSSProperties => { + return { + display: "flex", + justifyContent: "center", + alignItems: "center", + margin: + layout.value === "horizontal" + ? "0 5px 0 0" + : isCollapse.value + ? "0 auto" + : "0 5px 0 0" + }; +}); + +const textClass = computed(() => { + const item = props.item; + const baseClass = "w-full! text-inherit!"; + if ( + layout.value !== "horizontal" && + isCollapse.value && + !toRaw(item.meta.icon) && + ((layout.value === "vertical" && item.parentId === null) || + (layout.value === "mix" && item.pathList.length === 2)) + ) { + return `${baseClass} min-w-[54px]! text-center! px-3!`; + } + return baseClass; +}); + +const expandCloseIcon = computed(() => { + if (!getConfig()?.MenuArrowIconNoTransition) return ""; + return { + "expand-close-icon": useRenderIcon(EpArrowDown), + "expand-open-icon": useRenderIcon(ArrowUp), + "collapse-close-icon": useRenderIcon(ArrowRight), + "collapse-open-icon": useRenderIcon(ArrowLeft) + }; +}); + +const onlyOneChild: menuType = ref(null); + +function hasOneShowingChild(children: menuType[] = [], parent: menuType) { + const showingChildren = children.filter((item: any) => { + onlyOneChild.value = item; + return true; + }); + + if (showingChildren[0]?.meta?.showParent) { + return false; + } + + if (showingChildren.length === 1) { + return true; + } + + if (showingChildren.length === 0) { + onlyOneChild.value = { ...parent, path: "", noShowingChildren: true }; + return true; + } + return false; +} + +function resolvePath(routePath) { + const httpReg = /^http(s?):\/\//; + if (httpReg.test(routePath) || httpReg.test(props.basePath)) { + return routePath || props.basePath; + } else { + return posix.resolve(props.basePath, routePath); + } +} +</script> + +<template> + <SidebarLinkItem + v-if=" + hasOneShowingChild(item.children, item) && + (!onlyOneChild.children || onlyOneChild.noShowingChildren) + " + :to="item" + > + <el-menu-item + :index="resolvePath(onlyOneChild.path)" + :class="{ 'submenu-title-noDropdown': !isNest }" + :style="getNoDropdownStyle" + v-bind="attrs" + > + <div + v-if="toRaw(item.meta.icon)" + class="sub-menu-icon" + :style="getSubMenuIconStyle" + > + <component + :is=" + useRenderIcon( + toRaw(onlyOneChild.meta.icon) || + (item.meta && toRaw(item.meta.icon)) + ) + " + /> + </div> + <el-text + v-if=" + (!item?.meta.icon && + isCollapse && + layout === 'vertical' && + item?.pathList?.length === 1) || + (!onlyOneChild.meta.icon && + isCollapse && + layout === 'mix' && + item?.pathList?.length === 2) + " + truncated + class="w-full! px-3! min-w-[54px]! text-center! text-inherit!" + > + {{ onlyOneChild.meta.title }} + </el-text> + + <template #title> + <div :style="getDivStyle"> + <ReText + :tippyProps="{ + offset: [0, -10], + theme: tooltipEffect + }" + class="w-full! text-inherit!" + > + {{ onlyOneChild.meta.title }} + </ReText> + <SidebarExtraIcon :extraIcon="onlyOneChild.meta.extraIcon" /> + </div> + </template> + </el-menu-item> + </SidebarLinkItem> + <el-sub-menu + v-else + ref="subMenu" + teleported + :index="resolvePath(item.path)" + v-bind="expandCloseIcon" + > + <template #title> + <div + v-if="toRaw(item.meta.icon)" + :style="getSubMenuIconStyle" + class="sub-menu-icon" + > + <component :is="useRenderIcon(item.meta && toRaw(item.meta.icon))" /> + </div> + <ReText + v-if=" + layout === 'mix' && toRaw(item.meta.icon) + ? !isCollapse || item?.pathList?.length !== 2 + : !( + layout === 'vertical' && + isCollapse && + toRaw(item.meta.icon) && + item.parentId === null + ) + " + :tippyProps="{ + offset: [0, -10], + theme: tooltipEffect + }" + :class="textClass" + > + {{ item.meta.title }} + </ReText> + <SidebarExtraIcon v-if="!isCollapse" :extraIcon="item.meta.extraIcon" /> + </template> + + <sidebar-item + v-for="child in item.children" + :key="child.path" + :is-nest="true" + :item="child" + :base-path="resolvePath(child.path)" + class="nest-menu" + /> + </el-sub-menu> +</template> diff --git a/src/layout/components/lay-sidebar/components/SidebarLeftCollapse.vue b/src/layout/components/lay-sidebar/components/SidebarLeftCollapse.vue new file mode 100644 index 0000000..50e5125 --- /dev/null +++ b/src/layout/components/lay-sidebar/components/SidebarLeftCollapse.vue @@ -0,0 +1,69 @@ +<script setup lang="ts"> +import { computed } from "vue"; +import { useGlobal } from "@pureadmin/utils"; +import { useNav } from "@/layout/hooks/useNav"; + +import MenuFold from "~icons/ri/menu-fold-fill"; + +interface Props { + isActive?: boolean; +} + +withDefaults(defineProps<Props>(), { + isActive: false +}); + +const { tooltipEffect } = useNav(); + +const iconClass = computed(() => { + return [ + "ml-4", + "mb-1", + "w-[16px]", + "h-[16px]", + "inline-block!", + "align-middle", + "cursor-pointer", + "duration-[100ms]" + ]; +}); + +const { $storage } = useGlobal<GlobalPropertiesApi>(); +const themeColor = computed(() => $storage.layout?.themeColor); + +const emit = defineEmits<{ + (e: "toggleClick"): void; +}>(); + +const toggleClick = () => { + emit("toggleClick"); +}; +</script> + +<template> + <div class="left-collapse"> + <IconifyIconOffline + v-tippy="{ + content: isActive ? '鐐瑰嚮鎶樺彔' : '鐐瑰嚮灞曞紑', + theme: tooltipEffect, + hideOnClick: 'toggle', + placement: 'right' + }" + :icon="MenuFold" + :class="[iconClass, themeColor === 'light' ? '' : 'text-primary']" + :style="{ transform: isActive ? 'none' : 'rotateY(180deg)' }" + @click="toggleClick" + /> + </div> +</template> + +<style lang="scss" scoped> +.left-collapse { + position: absolute; + bottom: 0; + width: 100%; + height: 40px; + line-height: 40px; + box-shadow: 0 0 6px -3px var(--el-color-primary); +} +</style> diff --git a/src/layout/components/lay-sidebar/components/SidebarLinkItem.vue b/src/layout/components/lay-sidebar/components/SidebarLinkItem.vue new file mode 100644 index 0000000..8911c12 --- /dev/null +++ b/src/layout/components/lay-sidebar/components/SidebarLinkItem.vue @@ -0,0 +1,32 @@ +<script setup lang="ts"> +import { computed } from "vue"; +import { isUrl } from "@pureadmin/utils"; +import { menuType } from "@/layout/types"; + +const props = defineProps<{ + to: menuType; +}>(); + +const isExternalLink = computed(() => isUrl(props.to.name)); +const getLinkProps = (item: menuType) => { + if (isExternalLink.value) { + return { + href: item.name, + target: "_blank", + rel: "noopener" + }; + } + return { + to: item + }; +}; +</script> + +<template> + <component + :is="isExternalLink ? 'a' : 'router-link'" + v-bind="getLinkProps(to)" + > + <slot /> + </component> +</template> diff --git a/src/layout/components/lay-sidebar/components/SidebarLogo.vue b/src/layout/components/lay-sidebar/components/SidebarLogo.vue new file mode 100644 index 0000000..ccbc7ab --- /dev/null +++ b/src/layout/components/lay-sidebar/components/SidebarLogo.vue @@ -0,0 +1,72 @@ +<script setup lang="ts"> +import { getTopMenu } from "@/router/utils"; +import { useNav } from "@/layout/hooks/useNav"; + +defineProps({ + collapse: Boolean +}); + +const { title, getLogo } = useNav(); +</script> + +<template> + <div class="sidebar-logo-container" :class="{ collapses: collapse }"> + <transition name="sidebarLogoFade"> + <router-link + v-if="collapse" + key="collapse" + :title="title" + class="sidebar-logo-link" + :to="getTopMenu()?.path ?? '/'" + > + <img :src="getLogo()" alt="logo" /> + <span class="sidebar-title">{{ title }}</span> + </router-link> + <router-link + v-else + key="expand" + :title="title" + class="sidebar-logo-link" + :to="getTopMenu()?.path ?? '/'" + > + <img :src="getLogo()" alt="logo" /> + <span class="sidebar-title">{{ title }}</span> + </router-link> + </transition> + </div> +</template> + +<style lang="scss" scoped> +.sidebar-logo-container { + position: relative; + width: 100%; + height: 48px; + overflow: hidden; + + .sidebar-logo-link { + display: flex; + flex-wrap: nowrap; + align-items: center; + height: 100%; + padding-left: 10px; + + img { + display: inline-block; + height: 32px; + } + + .sidebar-title { + display: inline-block; + height: 32px; + margin: 2px 0 0 12px; + overflow: hidden; + text-overflow: ellipsis; + font-size: 18px; + font-weight: 600; + line-height: 32px; + color: var(--pure-theme-sub-menu-active-text); + white-space: nowrap; + } + } +} +</style> diff --git a/src/layout/components/lay-sidebar/components/SidebarTopCollapse.vue b/src/layout/components/lay-sidebar/components/SidebarTopCollapse.vue new file mode 100644 index 0000000..350df33 --- /dev/null +++ b/src/layout/components/lay-sidebar/components/SidebarTopCollapse.vue @@ -0,0 +1,33 @@ +<script setup lang="ts"> +import MenuFold from "~icons/ri/menu-fold-fill"; +import MenuUnfold from "~icons/ri/menu-unfold-fill"; + +interface Props { + isActive?: boolean; +} + +withDefaults(defineProps<Props>(), { + isActive: false +}); + +const emit = defineEmits<{ + (e: "toggleClick"): void; +}>(); + +const toggleClick = () => { + emit("toggleClick"); +}; +</script> + +<template> + <div + class="px-3 mr-1 navbar-bg-hover" + :title="isActive ? '鐐瑰嚮鎶樺彔' : '鐐瑰嚮灞曞紑'" + @click="toggleClick" + > + <IconifyIconOffline + :icon="isActive ? MenuFold : MenuUnfold" + class="inline-block! align-middle hover:text-primary dark:hover:text-white!" + /> + </div> +</template> diff --git a/src/layout/components/lay-tag/components/TagChrome.vue b/src/layout/components/lay-tag/components/TagChrome.vue new file mode 100644 index 0000000..137365b --- /dev/null +++ b/src/layout/components/lay-tag/components/TagChrome.vue @@ -0,0 +1,33 @@ +<template> + <svg class="w-full h-full"> + <defs> + <symbol id="geometry-left" viewBox="0 0 214 36"> + <path d="M17 0h197v36H0v-2c4.5 0 9-3.5 9-8V8c0-4.5 3.5-8 8-8z" /> + </symbol> + <symbol id="geometry-right" viewBox="0 0 214 36"> + <use xlink:href="#geometry-left" /> + </symbol> + <clipPath> + <rect width="100%" height="100%" x="0" /> + </clipPath> + </defs> + <svg width="51%" height="100%"> + <use + xlink:href="#geometry-left" + width="214" + height="36" + fill="currentColor" + /> + </svg> + <g transform="scale(-1, 1)"> + <svg width="51%" height="100%" x="-100%" y="0"> + <use + xlink:href="#geometry-right" + width="214" + height="36" + fill="currentColor" + /> + </svg> + </g> + </svg> +</template> diff --git a/src/layout/components/lay-tag/index.scss b/src/layout/components/lay-tag/index.scss new file mode 100644 index 0000000..e399680 --- /dev/null +++ b/src/layout/components/lay-tag/index.scss @@ -0,0 +1,371 @@ +@keyframes schedule-in-width { + from { + width: 0; + } + + to { + width: 100%; + } +} + +@keyframes schedule-out-width { + from { + width: 100%; + } + + to { + width: 0; + } +} + +.tags-view { + position: relative; + display: flex; + align-items: center; + width: 100%; + font-size: 14px; + color: var(--el-text-color-primary); + background: #fff; + box-shadow: 0 0 1px #888; + + .scroll-item { + position: relative; + display: inline-block; + height: 34px; + padding-left: 6px; + line-height: 34px; + cursor: pointer; + transition: all 0.4s; + + &:not(:first-child) { + padding-right: 24px; + } + + &.chrome-item { + padding-right: 0; + padding-left: 0; + margin-right: -18px; + box-shadow: none; + } + + .el-icon-close { + position: absolute; + top: 50%; + display: inline-flex; + align-items: center; + justify-content: center; + width: 18px; + height: 18px; + color: var(--el-color-primary); + cursor: pointer; + border-radius: 4px; + transform: translate(0, -50%); + transition: + background-color 0.12s, + color 0.12s; + + &:hover { + color: rgb(0 0 0 / 88%) !important; + background-color: rgb(0 0 0 / 6%); + } + } + } + + .tag-title { + padding: 0 4px; + color: var(--el-text-color-primary); + text-decoration: none; + } + + .scroll-container { + position: relative; + flex: 1; + overflow: hidden; + white-space: nowrap; + + &.chrome-scroll-container { + padding-top: 4px; + + .fixed-tag { + padding: 0 !important; + } + } + + .tab { + position: relative; + float: left; + overflow: visible; + white-space: nowrap; + list-style: none; + + .scroll-item { + transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1); + + &:nth-child(1) { + padding: 0 12px; + } + + &.chrome-item { + &:nth-child(1) { + padding: 0; + } + } + } + + .fixed-tag { + padding: 0 12px; + } + } + } + + /* 鍙抽敭鑿滃崟 */ + .contextmenu { + position: absolute; + padding: 5px 0; + margin: 0; + font-size: 13px; + font-weight: normal; + color: var(--el-text-color-primary); + white-space: nowrap; + outline: 0; + list-style-type: none; + background: #fff; + border-radius: 4px; + box-shadow: 0 2px 8px rgb(0 0 0 / 15%); + + li { + display: flex; + align-items: center; + width: 100%; + padding: 7px 12px; + margin: 0; + cursor: pointer; + + &:hover { + color: var(--el-color-primary); + } + + svg { + display: block; + margin-right: 0.5em; + } + } + } +} + +.el-dropdown-menu { + li { + display: flex; + align-items: center; + width: 100%; + margin: 0; + cursor: pointer; + + svg { + display: block; + margin-right: 0.5em; + } + } +} + +.el-dropdown-menu__item:not(.is-disabled):hover { + color: #606266; + background: #f0f0f0; +} + +:deep(.el-dropdown-menu__item) i { + margin-right: 10px; +} + +:deep(.el-dropdown-menu__item--divided) { + margin: 1px 0; +} + +.el-dropdown-menu__item--divided::before { + margin: 0; +} + +.el-dropdown-menu__item.is-disabled { + cursor: not-allowed; +} + +.scroll-item.is-active { + position: relative; + color: #fff; + box-shadow: 0 0 0.7px #888; + + .chrome-tab { + z-index: 10; + } + + .chrome-tab__bg { + color: var(--el-color-primary-light-9) !important; + } + + .tag-title { + color: var(--el-color-primary) !important; + } + + .chrome-close-btn { + color: var(--el-color-primary); + + &:hover { + background-color: var(--el-color-primary); + } + } + + .chrome-tab-divider { + opacity: 0; + } +} + +.arrow-left, +.arrow-right, +.arrow-down { + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 34px; + color: var(--el-text-color-primary); + + svg { + width: 20px; + height: 20px; + } +} + +.arrow-left { + box-shadow: 5px 0 5px -6px #ccc; + + &:hover { + cursor: w-resize; + } +} + +.arrow-right { + border-right: 0.5px solid #ccc; + box-shadow: -5px 0 5px -6px #ccc; + + &:hover { + cursor: e-resize; + } +} + +/* 鍗$墖妯″紡涓嬮紶鏍囩Щ鍏ユ樉绀鸿摑鑹茶竟妗� */ +.card-in { + color: var(--el-color-primary); + + .tag-title { + color: var(--el-color-primary); + } +} + +/* 鍗$墖妯″紡涓嬮紶鏍囩Щ鍑洪殣钘忚摑鑹茶竟妗� */ +.card-out { + color: #666; + border: none; + + .tag-title { + color: #666; + } +} + +/* 鐏靛姩妯″紡 */ +.schedule-active { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 2px; + background: var(--el-color-primary); +} + +/* 鐏靛姩妯″紡涓嬮紶鏍囩Щ鍏ユ樉绀鸿摑鑹茶繘搴︽潯 */ +.schedule-in { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 2px; + background: var(--el-color-primary); + animation: schedule-in-width 200ms ease-in; +} + +/* 鐏靛姩妯″紡涓嬮紶鏍囩Щ鍑洪殣钘忚摑鑹茶繘搴︽潯 */ +.schedule-out { + position: absolute; + bottom: 0; + left: 0; + width: 0; + height: 2px; + background: var(--el-color-primary); + animation: schedule-out-width 200ms ease-in; +} + +/* 璋锋瓕椋庢牸鐨勯〉绛� */ +.chrome-tab { + position: relative; + display: inline-flex; + gap: 16px; + align-items: center; + justify-content: center; + padding: 0 24px; + white-space: nowrap; + cursor: pointer; + + .tag-title { + padding: 0; + } + + .chrome-tab-divider { + position: absolute; + right: 7px; + width: 1px; + height: 14px; + background-color: #2b2d2f; + } + + &:hover { + z-index: 10; + + .chrome-tab__bg { + color: #dee1e6; + } + + .tag-title { + color: #1f1f1f; + } + + .chrome-tab-divider { + opacity: 0; + } + } + + .chrome-tab__bg { + position: absolute; + top: 0; + left: 0; + z-index: -10; + width: 100%; + height: 100%; + color: transparent; + pointer-events: none; + } + + .chrome-close-btn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + color: #666; + border-radius: 50%; + + &:hover { + color: white; + background-color: #b1b3b8; + } + } +} diff --git a/src/layout/components/lay-tag/index.vue b/src/layout/components/lay-tag/index.vue new file mode 100644 index 0000000..a21e389 --- /dev/null +++ b/src/layout/components/lay-tag/index.vue @@ -0,0 +1,684 @@ +<script setup lang="ts"> +import { emitter } from "@/utils/mitt"; +import { RouteConfigs } from "../../types"; +import { useTags } from "../../hooks/useTag"; +import { routerArrays } from "@/layout/types"; +import { onClickOutside } from "@vueuse/core"; +import TagChrome from "./components/TagChrome.vue"; +import { handleAliveRoute, getTopMenu } from "@/router/utils"; +import { useSettingStoreHook } from "@/store/modules/settings"; +import { useMultiTagsStoreHook } from "@/store/modules/multiTags"; +import { usePermissionStoreHook } from "@/store/modules/permission"; +import { ref, watch, unref, toRaw, nextTick, onBeforeUnmount } from "vue"; +import { + delay, + isEqual, + isAllEmpty, + useResizeObserver +} from "@pureadmin/utils"; + +import ExitFullscreen from "~icons/ri/fullscreen-exit-fill"; +import Fullscreen from "~icons/ri/fullscreen-fill"; +import ArrowDown from "~icons/ri/arrow-down-s-line"; +import ArrowRightSLine from "~icons/ri/arrow-right-s-line"; +import ArrowLeftSLine from "~icons/ri/arrow-left-s-line"; + +const { + Close, + route, + router, + visible, + showTags, + instance, + multiTags, + tagsViews, + buttonTop, + buttonLeft, + showModel, + translateX, + isFixedTag, + pureSetting, + activeIndex, + getTabStyle, + isScrolling, + iconIsActive, + linkIsActive, + currentSelect, + scheduleIsActive, + getContextMenuStyle, + closeMenu, + onMounted, + onMouseenter, + onMouseleave, + onContentFullScreen +} = useTags(); + +const tabDom = ref(); +const containerDom = ref(); +const scrollbarDom = ref(); +const contextmenuRef = ref(); +const isShowArrow = ref(false); +const topPath = getTopMenu()?.path; +const { VITE_HIDE_HOME } = import.meta.env; +const fixedTags = [ + ...routerArrays, + ...usePermissionStoreHook().flatteningRoutes.filter(v => v?.meta?.fixedTag) +]; + +const dynamicTagView = async () => { + await nextTick(); + const index = multiTags.value.findIndex(item => { + if (!isAllEmpty(route.query)) { + return isEqual(route.query, item.query); + } else if (!isAllEmpty(route.params)) { + return isEqual(route.params, item.params); + } else { + return route.path === item.path; + } + }); + moveToView(index); +}; + +const moveToView = async (index: number): Promise<void> => { + await nextTick(); + const tabNavPadding = 10; + if (!instance.refs["dynamic" + index]) return; + const tabItemEl = instance.refs["dynamic" + index][0]; + const tabItemElOffsetLeft = (tabItemEl as HTMLElement)?.offsetLeft; + const tabItemOffsetWidth = (tabItemEl as HTMLElement)?.offsetWidth; + // 鏍囩椤靛鑸爮鍙闀垮害锛堜笉鍖呭惈婧㈠嚭閮ㄥ垎锛� + const scrollbarDomWidth = scrollbarDom.value + ? scrollbarDom.value?.offsetWidth + : 0; + + // 宸叉湁鏍囩椤垫�婚暱搴︼紙鍖呭惈婧㈠嚭閮ㄥ垎锛� + const tabDomWidth = tabDom.value ? tabDom.value?.offsetWidth : 0; + + scrollbarDomWidth <= tabDomWidth + ? (isShowArrow.value = true) + : (isShowArrow.value = false); + if (tabDomWidth < scrollbarDomWidth || tabItemElOffsetLeft === 0) { + translateX.value = 0; + } else if (tabItemElOffsetLeft < -translateX.value) { + // 鏍囩鍦ㄥ彲瑙嗗尯鍩熷乏渚� + translateX.value = -tabItemElOffsetLeft + tabNavPadding; + } else if ( + tabItemElOffsetLeft > -translateX.value && + tabItemElOffsetLeft + tabItemOffsetWidth < + -translateX.value + scrollbarDomWidth + ) { + // 鏍囩鍦ㄥ彲瑙嗗尯鍩� + translateX.value = Math.min( + 0, + scrollbarDomWidth - + tabItemOffsetWidth - + tabItemElOffsetLeft - + tabNavPadding + ); + } else { + // 鏍囩鍦ㄥ彲瑙嗗尯鍩熷彸渚� + translateX.value = -( + tabItemElOffsetLeft - + (scrollbarDomWidth - tabNavPadding - tabItemOffsetWidth) + ); + } +}; + +const handleScroll = (offset: number): void => { + const scrollbarDomWidth = scrollbarDom.value + ? scrollbarDom.value?.offsetWidth + : 0; + const tabDomWidth = tabDom.value ? tabDom.value.offsetWidth : 0; + if (offset > 0) { + translateX.value = Math.min(0, translateX.value + offset); + } else { + if (scrollbarDomWidth < tabDomWidth) { + if (translateX.value >= -(tabDomWidth - scrollbarDomWidth)) { + translateX.value = Math.max( + translateX.value + offset, + scrollbarDomWidth - tabDomWidth + ); + } + } else { + translateX.value = 0; + } + } + isScrolling.value = false; +}; + +const handleWheel = (event: WheelEvent): void => { + isScrolling.value = true; + const scrollIntensity = Math.abs(event.deltaX) + Math.abs(event.deltaY); + let offset = 0; + if (event.deltaX < 0) { + offset = scrollIntensity > 0 ? scrollIntensity : 100; + } else { + offset = scrollIntensity > 0 ? -scrollIntensity : -100; + } + + smoothScroll(offset); +}; + +const smoothScroll = (offset: number): void => { + // 姣忓抚婊氬姩鐨勮窛绂� + const scrollAmount = 20; + let remaining = Math.abs(offset); + + const scrollStep = () => { + const scrollOffset = Math.sign(offset) * Math.min(scrollAmount, remaining); + handleScroll(scrollOffset); + remaining -= Math.abs(scrollOffset); + + if (remaining > 0) { + requestAnimationFrame(scrollStep); + } + }; + + requestAnimationFrame(scrollStep); +}; + +function dynamicRouteTag(value: string): void { + const hasValue = multiTags.value.some(item => { + return item.path === value; + }); + + function concatPath(arr: object[], value: string) { + if (!hasValue) { + arr.forEach((arrItem: any) => { + if (arrItem.path === value) { + useMultiTagsStoreHook().handleTags("push", { + path: value, + meta: arrItem.meta, + name: arrItem.name + }); + } else { + if (arrItem.children && arrItem.children.length > 0) { + concatPath(arrItem.children, value); + } + } + }); + } + } + concatPath(router.options.routes as any, value); +} + +/** 鍒锋柊璺敱 */ +function onFresh() { + const { fullPath, query } = unref(route); + router.replace({ + path: "/redirect" + fullPath, + query + }); + handleAliveRoute(route as ToRouteType, "refresh"); +} + +function deleteDynamicTag(obj: any, current: any, tag?: string) { + const valueIndex: number = multiTags.value.findIndex((item: any) => { + if (item.query) { + if (item.path === obj.path) { + return item.query === obj.query; + } + } else if (item.params) { + if (item.path === obj.path) { + return item.params === obj.params; + } + } else { + return item.path === obj.path; + } + }); + + const spliceRoute = ( + startIndex?: number, + length?: number, + other?: boolean + ): void => { + if (other) { + useMultiTagsStoreHook().handleTags( + "equal", + [ + VITE_HIDE_HOME === "false" ? fixedTags : toRaw(getTopMenu()), + obj + ].flat() + ); + } else { + useMultiTagsStoreHook().handleTags("splice", "", { + startIndex, + length + }) as any; + } + dynamicTagView(); + }; + + if (tag === "other") { + spliceRoute(1, 1, true); + } else if (tag === "left") { + spliceRoute(fixedTags.length, valueIndex - 1, true); + } else if (tag === "right") { + spliceRoute(valueIndex + 1, multiTags.value.length); + } else { + // 浠庡綋鍓嶅尮閰嶅埌鐨勮矾寰勪腑鍒犻櫎 + spliceRoute(valueIndex, 1); + } + const newRoute = useMultiTagsStoreHook().handleTags("slice"); + if (current === route.path) { + // 濡傛灉鍒犻櫎褰撳墠婵�娲籺ag灏辫嚜鍔ㄥ垏鎹㈠埌鏈�鍚庝竴涓猼ag + if (tag === "left") return; + if (newRoute[0]?.query) { + router.push({ name: newRoute[0].name, query: newRoute[0].query }); + } else if (newRoute[0]?.params) { + router.push({ name: newRoute[0].name, params: newRoute[0].params }); + } else { + router.push({ path: newRoute[0].path }); + } + } else { + if (!multiTags.value.length) return; + if (multiTags.value.some(item => item.path === route.path)) return; + if (newRoute[0]?.query) { + router.push({ name: newRoute[0].name, query: newRoute[0].query }); + } else if (newRoute[0]?.params) { + router.push({ name: newRoute[0].name, params: newRoute[0].params }); + } else { + router.push({ path: newRoute[0].path }); + } + } +} + +function deleteMenu(item, tag?: string) { + deleteDynamicTag(item, item.path, tag); + handleAliveRoute(route as ToRouteType); +} + +function onClickDrop(key, item, selectRoute?: RouteConfigs) { + if (item && item.disabled) return; + + let selectTagRoute; + if (selectRoute) { + selectTagRoute = { + path: selectRoute.path, + meta: selectRoute.meta, + name: selectRoute.name, + query: selectRoute?.query, + params: selectRoute?.params + }; + } else { + selectTagRoute = { path: route.path, meta: route.meta }; + } + + // 褰撳墠璺敱淇℃伅 + switch (key) { + case 0: + // 鍒锋柊璺敱 + onFresh(); + break; + case 1: + // 鍏抽棴褰撳墠鏍囩椤� + deleteMenu(selectTagRoute); + break; + case 2: + // 鍏抽棴宸︿晶鏍囩椤� + deleteMenu(selectTagRoute, "left"); + break; + case 3: + // 鍏抽棴鍙充晶鏍囩椤� + deleteMenu(selectTagRoute, "right"); + break; + case 4: + // 鍏抽棴鍏朵粬鏍囩椤� + deleteMenu(selectTagRoute, "other"); + break; + case 5: + // 鍏抽棴鍏ㄩ儴鏍囩椤� + useMultiTagsStoreHook().handleTags("splice", "", { + startIndex: fixedTags.length, + length: multiTags.value.length + }); + router.push(topPath); + // router.push(fixedTags[fixedTags.length - 1]?.path); + handleAliveRoute(route as ToRouteType); + break; + case 6: + // 鍐呭鍖哄叏灞� + onContentFullScreen(); + setTimeout(() => { + if (pureSetting.hiddenSideBar) { + tagsViews[6].icon = ExitFullscreen; + tagsViews[6].text = "鍐呭鍖洪��鍑哄叏灞�"; + } else { + tagsViews[6].icon = Fullscreen; + tagsViews[6].text = "鍐呭鍖哄叏灞�"; + } + }, 100); + break; + } + setTimeout(() => { + showMenuModel(route.fullPath, route.query); + }); +} + +function handleCommand(command: any) { + const { key, item } = command; + onClickDrop(key, item); +} + +/** 瑙﹀彂鍙抽敭涓彍鍗曠殑鐐瑰嚮浜嬩欢 */ +function selectTag(key, item) { + closeMenu(); + onClickDrop(key, item, currentSelect.value); +} + +function showMenus(value: boolean) { + Array.of(1, 2, 3, 4, 5).forEach(v => { + tagsViews[v].show = value; + }); +} + +function disabledMenus(value: boolean, fixedTag = false) { + Array.of(1, 2, 3, 4, 5).forEach(v => { + tagsViews[v].disabled = value; + }); + if (fixedTag) { + tagsViews[2].show = false; + tagsViews[2].disabled = true; + } +} + +/** 妫�鏌ュ綋鍓嶅彸閿殑鑿滃崟涓よ竟鏄惁瀛樺湪鍒殑鑿滃崟锛屽鏋滃乏渚х殑鑿滃崟鏄《绾ц彍鍗曪紝鍒欎笉鏄剧ず鍏抽棴宸︿晶鏍囩椤碉紝濡傛灉鍙充晶娌℃湁鑿滃崟锛屽垯涓嶆樉绀哄叧闂彸渚ф爣绛鹃〉 */ +function showMenuModel( + currentPath: string, + query: object = {}, + refresh = false +) { + const allRoute = multiTags.value; + const routeLength = multiTags.value.length; + let currentIndex = -1; + if (isAllEmpty(query)) { + currentIndex = allRoute.findIndex(v => v.path === currentPath); + } else { + currentIndex = allRoute.findIndex(v => isEqual(v.query, query)); + } + function fixedTagDisabled() { + if (allRoute[currentIndex]?.meta?.fixedTag) { + Array.of(1, 2, 3, 4, 5).forEach(v => { + tagsViews[v].disabled = true; + }); + } + } + + showMenus(true); + + if (refresh) { + tagsViews[0].show = true; + } + + /** + * currentIndex涓�1鏃讹紝宸︿晶鐨勮彍鍗曢《绾ц彍鍗曪紝鍒欎笉鏄剧ず鍏抽棴宸︿晶鏍囩椤� + * 濡傛灉currentIndex绛変簬routeLength-1锛屽彸渚ф病鏈夎彍鍗曪紝鍒欎笉鏄剧ず鍏抽棴鍙充晶鏍囩椤� + */ + if (currentIndex === 1 && routeLength !== 2) { + // 宸︿晶鐨勮彍鍗曟槸椤剁骇鑿滃崟锛屽彸渚у瓨鍦ㄥ埆鐨勮彍鍗� + tagsViews[2].show = false; + Array.of(1, 3, 4, 5).forEach(v => { + tagsViews[v].disabled = false; + }); + tagsViews[2].disabled = true; + fixedTagDisabled(); + } else if (currentIndex === 1 && routeLength === 2) { + disabledMenus(false); + // 宸︿晶鐨勮彍鍗曟槸椤剁骇鑿滃崟锛屽彸渚т笉瀛樺湪鍒殑鑿滃崟 + Array.of(2, 3, 4).forEach(v => { + tagsViews[v].show = false; + tagsViews[v].disabled = true; + }); + fixedTagDisabled(); + } else if (routeLength - 1 === currentIndex && currentIndex !== 0) { + // 褰撳墠璺敱鏄墍鏈夎矾鐢变腑鐨勬渶鍚庝竴涓� + tagsViews[3].show = false; + Array.of(1, 2, 4, 5).forEach(v => { + tagsViews[v].disabled = false; + }); + tagsViews[3].disabled = true; + if (allRoute[currentIndex - 1]?.meta?.fixedTag) { + tagsViews[2].show = false; + tagsViews[2].disabled = true; + } + fixedTagDisabled(); + } else if (currentIndex === 0 || currentPath === `/redirect${topPath}`) { + // 褰撳墠璺敱涓洪《绾ц彍鍗� + disabledMenus(true); + } else { + disabledMenus(false, allRoute[currentIndex - 1]?.meta?.fixedTag); + fixedTagDisabled(); + } +} + +function openMenu(tag, e) { + closeMenu(); + if (tag.path === topPath || tag?.meta?.fixedTag) { + // 鍙抽敭鑿滃崟涓洪《绾ц彍鍗曟垨鎷ユ湁 fixedTag 灞炴�э紝鍙樉绀哄埛鏂� + showMenus(false); + tagsViews[0].show = true; + } else if (route.path !== tag.path && route.name !== tag.name) { + // 鍙抽敭鑿滃崟涓嶅尮閰嶅綋鍓嶈矾鐢憋紝闅愯棌鍒锋柊 + tagsViews[0].show = false; + showMenuModel(tag.path, tag.query); + } else if (multiTags.value.length === 2 && route.path !== tag.path) { + showMenus(true); + // 鍙湁涓や釜鏍囩鏃朵笉鏄剧ず鍏抽棴鍏朵粬鏍囩椤� + tagsViews[4].show = false; + } else if (route.path === tag.path) { + // 鍙抽敭褰撳墠婵�娲荤殑鑿滃崟 + showMenuModel(tag.path, tag.query, true); + } + + currentSelect.value = tag; + const menuMinWidth = 140; + const offsetLeft = unref(containerDom).getBoundingClientRect().left; + const offsetWidth = unref(containerDom).offsetWidth; + const maxLeft = offsetWidth - menuMinWidth; + const left = e.clientX - offsetLeft + 5; + if (left > maxLeft) { + buttonLeft.value = maxLeft; + } else { + buttonLeft.value = left; + } + useSettingStoreHook().hiddenSideBar + ? (buttonTop.value = e.clientY) + : (buttonTop.value = e.clientY - 40); + nextTick(() => { + visible.value = true; + }); +} + +/** 瑙﹀彂tags鏍囩鍒囨崲 */ +function tagOnClick(item) { + const { name, path } = item; + if (name) { + if (item.query) { + router.push({ + name, + query: item.query + }); + } else if (item.params) { + router.push({ + name, + params: item.params + }); + } else { + router.push({ name }); + } + } else { + router.push({ path }); + } + emitter.emit("tagOnClick", item); +} + +onClickOutside(contextmenuRef, closeMenu, { + detectIframe: true +}); + +watch(route, () => { + activeIndex.value = -1; + dynamicTagView(); +}); + +onMounted(() => { + if (!instance) return; + + // 鏍规嵁褰撳墠璺敱鍒濆鍖栨搷浣滄爣绛鹃〉鐨勭鐢ㄧ姸鎬� + showMenuModel(route.fullPath); + + // 瑙﹀彂闅愯棌鏍囩椤� + emitter.on("tagViewsChange", (key: any) => { + if (unref(showTags as any) === key) return; + (showTags as any).value = key; + }); + + // 鏀瑰彉鏍囩椋庢牸 + emitter.on("tagViewsShowModel", key => { + showModel.value = key; + }); + + // 鎺ユ敹渚ц竟鏍忓垏鎹紶閫掕繃鏉ョ殑鍙傛暟 + emitter.on("changLayoutRoute", indexPath => { + dynamicRouteTag(indexPath); + setTimeout(() => { + showMenuModel(indexPath); + }); + }); + + useResizeObserver(scrollbarDom, dynamicTagView); + delay().then(() => dynamicTagView()); +}); + +onBeforeUnmount(() => { + // 瑙g粦`tagViewsChange`銆乣tagViewsShowModel`銆乣changLayoutRoute`鍏叡浜嬩欢锛岄槻姝㈠娆¤Е鍙� + emitter.off("tagViewsChange"); + emitter.off("tagViewsShowModel"); + emitter.off("changLayoutRoute"); +}); +</script> + +<template> + <div v-if="!showTags" ref="containerDom" class="tags-view"> + <span v-show="isShowArrow" class="arrow-left"> + <IconifyIconOffline :icon="ArrowLeftSLine" @click="handleScroll(200)" /> + </span> + <div + ref="scrollbarDom" + class="scroll-container" + :class="showModel === 'chrome' && 'chrome-scroll-container'" + @wheel.prevent="handleWheel" + > + <div ref="tabDom" class="tab select-none" :style="getTabStyle"> + <div + v-for="(item, index) in multiTags" + :ref="'dynamic' + index" + :key="index" + :class="[ + 'scroll-item is-closable', + linkIsActive(item), + showModel === 'chrome' && 'chrome-item', + isFixedTag(item) && 'fixed-tag' + ]" + @contextmenu.prevent="openMenu(item, $event)" + @mouseenter.prevent="onMouseenter(index)" + @mouseleave.prevent="onMouseleave(index)" + @click="tagOnClick(item)" + > + <template v-if="showModel !== 'chrome'"> + <span + class="tag-title dark:text-text_color_primary! dark:hover:text-primary!" + > + {{ item.meta.title }} + </span> + <span + v-if=" + isFixedTag(item) + ? false + : iconIsActive(item, index) || + (index === activeIndex && index !== 0) + " + class="el-icon-close" + @click.stop="deleteMenu(item)" + > + <IconifyIconOffline :icon="Close" /> + </span> + <span + v-if="showModel !== 'card'" + :ref="'schedule' + index" + :class="[scheduleIsActive(item)]" + /> + </template> + <div v-else class="chrome-tab"> + <div class="chrome-tab__bg"> + <TagChrome /> + </div> + <span class="tag-title"> + {{ item.meta.title }} + </span> + <span + v-if="isFixedTag(item) ? false : index !== 0" + class="chrome-close-btn" + @click.stop="deleteMenu(item)" + > + <IconifyIconOffline :icon="Close" /> + </span> + <span class="chrome-tab-divider" /> + </div> + </div> + </div> + </div> + <span v-show="isShowArrow" class="arrow-right"> + <IconifyIconOffline :icon="ArrowRightSLine" @click="handleScroll(-200)" /> + </span> + <!-- 鍙抽敭鑿滃崟鎸夐挳 --> + <transition name="el-zoom-in-top"> + <ul + v-show="visible" + ref="contextmenuRef" + :key="Math.random()" + :style="getContextMenuStyle" + class="contextmenu" + > + <div + v-for="(item, key) in tagsViews.slice(0, 6)" + :key="key" + style="display: flex; align-items: center" + > + <li v-if="item.show" @click="selectTag(key, item)"> + <IconifyIconOffline :icon="item.icon" /> + {{ item.text }} + </li> + </div> + </ul> + </transition> + <!-- 鍙充晶鍔熻兘鎸夐挳 --> + <el-dropdown + trigger="click" + placement="bottom-end" + @command="handleCommand" + > + <span class="arrow-down"> + <IconifyIconOffline :icon="ArrowDown" class="dark:text-white" /> + </span> + <template #dropdown> + <el-dropdown-menu> + <el-dropdown-item + v-for="(item, key) in tagsViews" + :key="key" + :command="{ key, item }" + :divided="item.divided" + :disabled="item.disabled" + > + <IconifyIconOffline :icon="item.icon" /> + {{ item.text }} + </el-dropdown-item> + </el-dropdown-menu> + </template> + </el-dropdown> + </div> +</template> + +<style lang="scss" scoped> +@import url("./index.scss"); +</style> diff --git a/src/layout/frame.vue b/src/layout/frame.vue new file mode 100644 index 0000000..a6549f7 --- /dev/null +++ b/src/layout/frame.vue @@ -0,0 +1,91 @@ +<script setup lang="ts"> +import { useRoute } from "vue-router"; +import { ref, unref, watch, onMounted, nextTick } from "vue"; + +defineOptions({ + name: "LayFrame" +}); + +const props = defineProps<{ + frameInfo?: { + frameSrc?: string; + fullPath?: string; + }; +}>(); + +const loading = ref(true); +const currentRoute = useRoute(); +const frameSrc = ref<string>(""); +const frameRef = ref<HTMLElement | null>(null); +if (unref(currentRoute.meta)?.frameSrc) { + frameSrc.value = unref(currentRoute.meta)?.frameSrc as string; +} +unref(currentRoute.meta)?.frameLoading === false && hideLoading(); + +function hideLoading() { + loading.value = false; +} + +function init() { + nextTick(() => { + const iframe = unref(frameRef); + if (!iframe) return; + const _frame = iframe as any; + if (_frame.attachEvent) { + _frame.attachEvent("onload", () => { + hideLoading(); + }); + } else { + iframe.onload = () => { + hideLoading(); + }; + } + }); +} + +watch( + () => currentRoute.fullPath, + path => { + if ( + currentRoute.name === "Redirect" && + path.includes(props.frameInfo?.fullPath) + ) { + frameSrc.value = path; // redirect鏃讹紝缃崲鎴愪换鎰忓�硷紝寰呴噸瀹氬悜鍚� 閲嶆柊璧嬪�� + loading.value = true; + } + // 閲嶆柊璧嬪�� + if (props.frameInfo?.fullPath === path) { + frameSrc.value = props.frameInfo?.frameSrc; + } + } +); + +onMounted(() => { + init(); +}); +</script> + +<template> + <div v-loading="loading" class="frame" element-loading-text="鍔犺浇涓�..."> + <iframe ref="frameRef" :src="frameSrc" class="frame-iframe" /> + </div> +</template> + +<style lang="scss" scoped> +.frame { + position: absolute; + inset: 0; + + .frame-iframe { + box-sizing: border-box; + width: 100%; + height: 100%; + overflow: hidden; + border: 0; + } +} + +.main-content { + margin: 2px 0 0 !important; +} +</style> diff --git a/src/layout/hooks/useBoolean.ts b/src/layout/hooks/useBoolean.ts new file mode 100644 index 0000000..1d14031 --- /dev/null +++ b/src/layout/hooks/useBoolean.ts @@ -0,0 +1,26 @@ +import { ref } from "vue"; + +export function useBoolean(initValue = false) { + const bool = ref(initValue); + + function setBool(value: boolean) { + bool.value = value; + } + function setTrue() { + setBool(true); + } + function setFalse() { + setBool(false); + } + function toggle() { + setBool(!bool.value); + } + + return { + bool, + setBool, + setTrue, + setFalse, + toggle + }; +} diff --git a/src/layout/hooks/useDataThemeChange.ts b/src/layout/hooks/useDataThemeChange.ts new file mode 100644 index 0000000..4b08dff --- /dev/null +++ b/src/layout/hooks/useDataThemeChange.ts @@ -0,0 +1,138 @@ +import { ref } from "vue"; +import { getConfig } from "@/config"; +import { useLayout } from "./useLayout"; +import { removeToken } from "@/utils/auth"; +import { routerArrays } from "@/layout/types"; +import { router, resetRouter } from "@/router"; +import type { themeColorsType } from "../types"; +import { useAppStoreHook } from "@/store/modules/app"; +import { useEpThemeStoreHook } from "@/store/modules/epTheme"; +import { useMultiTagsStoreHook } from "@/store/modules/multiTags"; +import { darken, lighten, useGlobal, storageLocal } from "@pureadmin/utils"; + +export function useDataThemeChange() { + const { layoutTheme, layout } = useLayout(); + const themeColors = ref<Array<themeColorsType>>([ + /* 浜櫧鑹� */ + { color: "#ffffff", themeColor: "light" }, + /* 閬撳钃� */ + { color: "#1b2a47", themeColor: "default" }, + /* 娣辩传缃楀叞鑹� */ + { color: "#722ed1", themeColor: "saucePurple" }, + /* 娣辩矇鑹� */ + { color: "#eb2f96", themeColor: "pink" }, + /* 鐚╃孩鑹� */ + { color: "#f5222d", themeColor: "dusk" }, + /* 姗欑孩鑹� */ + { color: "#fa541c", themeColor: "volcano" }, + /* 缁垮疂鐭� */ + { color: "#13c2c2", themeColor: "mingQing" }, + /* 閰告缁� */ + { color: "#52c41a", themeColor: "auroraGreen" } + ]); + + const { $storage } = useGlobal<GlobalPropertiesApi>(); + const dataTheme = ref<boolean>($storage?.layout?.darkMode); + const overallStyle = ref<string>($storage?.layout?.overallStyle); + const body = document.documentElement as HTMLElement; + + function toggleClass(flag: boolean, clsName: string, target?: HTMLElement) { + const targetEl = target || document.body; + let { className } = targetEl; + className = className.replace(clsName, "").trim(); + targetEl.className = flag ? `${className} ${clsName}` : className; + } + + /** 璁剧疆瀵艰埅涓婚鑹� */ + function setLayoutThemeColor( + theme = getConfig().Theme ?? "light", + isClick = true + ) { + layoutTheme.value.theme = theme; + document.documentElement.setAttribute("data-theme", theme); + // 濡傛灉闈瀒sClick锛屼繚鐣欎箣鍓嶇殑themeColor + const storageThemeColor = $storage.layout.themeColor; + $storage.layout = { + layout: layout.value, + theme, + darkMode: dataTheme.value, + sidebarStatus: $storage.layout?.sidebarStatus, + epThemeColor: $storage.layout?.epThemeColor, + themeColor: isClick ? theme : storageThemeColor, + overallStyle: overallStyle.value + }; + + if (theme === "default" || theme === "light") { + setEpThemeColor(getConfig().EpThemeColor); + } else { + const colors = themeColors.value.find(v => v.themeColor === theme); + setEpThemeColor(colors.color); + } + } + + function setPropertyPrimary(mode: string, i: number, color: string) { + document.documentElement.style.setProperty( + `--el-color-primary-${mode}-${i}`, + dataTheme.value ? darken(color, i / 10) : lighten(color, i / 10) + ); + } + + /** 璁剧疆 `element-plus` 涓婚鑹� */ + const setEpThemeColor = (color: string) => { + useEpThemeStoreHook().setEpThemeColor(color); + document.documentElement.style.setProperty("--el-color-primary", color); + for (let i = 1; i <= 2; i++) { + setPropertyPrimary("dark", i, color); + } + for (let i = 1; i <= 9; i++) { + setPropertyPrimary("light", i, color); + } + }; + + /** 娴呰壊銆佹繁鑹叉暣浣撻鏍煎垏鎹� */ + function dataThemeChange(overall?: string) { + overallStyle.value = overall; + if (useEpThemeStoreHook().epTheme === "light" && dataTheme.value) { + setLayoutThemeColor("default", false); + } else { + setLayoutThemeColor(useEpThemeStoreHook().epTheme, false); + } + + if (dataTheme.value) { + document.documentElement.classList.add("dark"); + } else { + if ($storage.layout.themeColor === "light") { + setLayoutThemeColor("light", false); + } + document.documentElement.classList.remove("dark"); + } + } + + /** 娓呯┖缂撳瓨骞惰繑鍥炵櫥褰曢〉 */ + function onReset() { + removeToken(); + storageLocal().clear(); + const { Grey, Weak, MultiTagsCache, EpThemeColor, Layout } = getConfig(); + useAppStoreHook().setLayout(Layout); + setEpThemeColor(EpThemeColor); + useMultiTagsStoreHook().multiTagsCacheChange(MultiTagsCache); + toggleClass(Grey, "html-grey", document.querySelector("html")); + toggleClass(Weak, "html-weakness", document.querySelector("html")); + router.push("/login"); + useMultiTagsStoreHook().handleTags("equal", [...routerArrays]); + resetRouter(); + } + + return { + body, + dataTheme, + overallStyle, + layoutTheme, + themeColors, + onReset, + toggleClass, + dataThemeChange, + setEpThemeColor, + setLayoutThemeColor + }; +} diff --git a/src/layout/hooks/useLayout.ts b/src/layout/hooks/useLayout.ts new file mode 100644 index 0000000..a45ea4f --- /dev/null +++ b/src/layout/hooks/useLayout.ts @@ -0,0 +1,58 @@ +import { computed } from "vue"; +import { routerArrays } from "../types"; +import { useGlobal } from "@pureadmin/utils"; +import { useMultiTagsStore } from "@/store/modules/multiTags"; + +export function useLayout() { + const { $storage, $config } = useGlobal<GlobalPropertiesApi>(); + + const initStorage = () => { + /** 璺敱 */ + if ( + useMultiTagsStore().multiTagsCache && + (!$storage.tags || $storage.tags.length === 0) + ) { + $storage.tags = routerArrays; + } + /** 瀵艰埅 */ + if (!$storage.layout) { + $storage.layout = { + layout: $config?.Layout ?? "vertical", + theme: $config?.Theme ?? "light", + darkMode: $config?.DarkMode ?? false, + sidebarStatus: $config?.SidebarStatus ?? true, + epThemeColor: $config?.EpThemeColor ?? "#409EFF", + themeColor: $config?.Theme ?? "light", + overallStyle: $config?.OverallStyle ?? "light" + }; + } + /** 鐏拌壊妯″紡銆佽壊寮辨ā寮忋�侀殣钘忔爣绛鹃〉 */ + if (!$storage.configure) { + $storage.configure = { + grey: $config?.Grey ?? false, + weak: $config?.Weak ?? false, + hideTabs: $config?.HideTabs ?? false, + hideFooter: $config.HideFooter ?? true, + showLogo: $config?.ShowLogo ?? true, + showModel: $config?.ShowModel ?? "smart", + multiTagsCache: $config?.MultiTagsCache ?? false, + stretch: $config?.Stretch ?? false + }; + } + }; + + /** 娓呯┖缂撳瓨鍚庝粠platform-config.json璇诲彇榛樿閰嶇疆骞惰祴鍊煎埌storage涓� */ + const layout = computed(() => { + return $storage?.layout.layout; + }); + + const layoutTheme = computed(() => { + return $storage.layout; + }); + + return { + layout, + layoutTheme, + initStorage + }; +} diff --git a/src/layout/hooks/useMultiFrame.ts b/src/layout/hooks/useMultiFrame.ts new file mode 100644 index 0000000..73a779d --- /dev/null +++ b/src/layout/hooks/useMultiFrame.ts @@ -0,0 +1,25 @@ +const MAP = new Map(); + +export const useMultiFrame = () => { + function setMap(path, Comp) { + MAP.set(path, Comp); + } + + function getMap(path?) { + if (path) { + return MAP.get(path); + } + return [...MAP.entries()]; + } + + function delMap(path) { + MAP.delete(path); + } + + return { + setMap, + getMap, + delMap, + MAP + }; +}; diff --git a/src/layout/hooks/useNav.ts b/src/layout/hooks/useNav.ts new file mode 100644 index 0000000..2448efb --- /dev/null +++ b/src/layout/hooks/useNav.ts @@ -0,0 +1,157 @@ +import { storeToRefs } from "pinia"; +import { getConfig } from "@/config"; +import { emitter } from "@/utils/mitt"; +import Avatar from "@/assets/user.jpg"; +import { getTopMenu } from "@/router/utils"; +import { useFullscreen } from "@vueuse/core"; +import type { routeMetaType } from "../types"; +import { useRouter, useRoute } from "vue-router"; +import { router, remainingPaths } from "@/router"; +import { computed, type CSSProperties } from "vue"; +import { useAppStoreHook } from "@/store/modules/app"; +import { useUserStoreHook } from "@/store/modules/user"; +import { useGlobal, isAllEmpty } from "@pureadmin/utils"; +import { usePermissionStoreHook } from "@/store/modules/permission"; +import ExitFullscreen from "~icons/ri/fullscreen-exit-fill"; +import Fullscreen from "~icons/ri/fullscreen-fill"; + +const errorInfo = + "The current routing configuration is incorrect, please check the configuration"; + +export function useNav() { + const route = useRoute(); + const pureApp = useAppStoreHook(); + const routers = useRouter().options.routes; + const { isFullscreen, toggle } = useFullscreen(); + const { wholeMenus } = storeToRefs(usePermissionStoreHook()); + /** 骞冲彴`layout`涓墍鏈塦el-tooltip`鐨刞effect`閰嶇疆锛岄粯璁light` */ + const tooltipEffect = getConfig()?.TooltipEffect ?? "light"; + + const getDivStyle = computed((): CSSProperties => { + return { + width: "100%", + display: "flex", + alignItems: "center", + justifyContent: "space-between", + overflow: "hidden" + }; + }); + + /** 澶村儚锛堝鏋滃ご鍍忎负绌哄垯浣跨敤 src/assets/user.jpg 锛� */ + const userAvatar = computed(() => { + return isAllEmpty(useUserStoreHook()?.avatar) + ? Avatar + : useUserStoreHook()?.avatar; + }); + + /** 鏄电О锛堝鏋滄樀绉颁负绌哄垯鏄剧ず鐢ㄦ埛鍚嶏級 */ + const username = computed(() => { + return isAllEmpty(useUserStoreHook()?.nickname) + ? useUserStoreHook()?.username + : useUserStoreHook()?.nickname; + }); + + const avatarsStyle = computed(() => { + return username.value ? { marginRight: "10px" } : ""; + }); + + const isCollapse = computed(() => { + return !pureApp.getSidebarStatus; + }); + + const device = computed(() => { + return pureApp.getDevice; + }); + + const { $storage, $config } = useGlobal<GlobalPropertiesApi>(); + const layout = computed(() => { + return $storage?.layout?.layout; + }); + + const title = computed(() => { + return $config.Title; + }); + + /** 鍔ㄦ�乼itle */ + function changeTitle(meta: routeMetaType) { + const Title = getConfig().Title; + if (Title) document.title = `${meta.title} | ${Title}`; + else document.title = meta.title; + } + + /** 閫�鍑虹櫥褰� */ + function logout() { + useUserStoreHook().logOut(); + } + + function backTopMenu() { + router.push(getTopMenu()?.path); + } + + function onPanel() { + emitter.emit("openPanel"); + } + + function toggleSideBar() { + pureApp.toggleSideBar(); + } + + function handleResize(menuRef) { + menuRef?.handleResize(); + } + + function resolvePath(route) { + if (!route.children) return console.error(errorInfo); + const httpReg = /^http(s?):\/\//; + const routeChildPath = route.children[0]?.path; + if (httpReg.test(routeChildPath)) { + return route.path + "/" + routeChildPath; + } else { + return routeChildPath; + } + } + + function menuSelect(indexPath: string) { + if (wholeMenus.value.length === 0 || isRemaining(indexPath)) return; + emitter.emit("changLayoutRoute", indexPath); + } + + /** 鍒ゆ柇璺緞鏄惁鍙備笌鑿滃崟 */ + function isRemaining(path: string) { + return remainingPaths.includes(path); + } + + /** 鑾峰彇`logo` */ + function getLogo() { + return new URL("/logo.svg", import.meta.url).href; + } + + return { + route, + title, + device, + layout, + logout, + routers, + $storage, + isFullscreen, + Fullscreen, + ExitFullscreen, + toggle, + backTopMenu, + onPanel, + getDivStyle, + changeTitle, + toggleSideBar, + menuSelect, + handleResize, + resolvePath, + getLogo, + isCollapse, + pureApp, + username, + userAvatar, + avatarsStyle, + tooltipEffect + }; +} diff --git a/src/layout/hooks/useTag.ts b/src/layout/hooks/useTag.ts new file mode 100644 index 0000000..1c2d254 --- /dev/null +++ b/src/layout/hooks/useTag.ts @@ -0,0 +1,245 @@ +import { + ref, + unref, + computed, + reactive, + onMounted, + type CSSProperties, + getCurrentInstance +} from "vue"; +import type { tagsViewsType } from "../types"; +import { useRoute, useRouter } from "vue-router"; +import { responsiveStorageNameSpace } from "@/config"; +import { useSettingStoreHook } from "@/store/modules/settings"; +import { useMultiTagsStoreHook } from "@/store/modules/multiTags"; +import { + isEqual, + isBoolean, + storageLocal, + toggleClass, + hasClass +} from "@pureadmin/utils"; + +import Fullscreen from "~icons/ri/fullscreen-fill"; +import CloseAllTags from "~icons/ri/subtract-line"; +import CloseOtherTags from "~icons/ri/text-spacing"; +import CloseRightTags from "~icons/ri/text-direction-l"; +import CloseLeftTags from "~icons/ri/text-direction-r"; +import RefreshRight from "~icons/ep/refresh-right"; +import Close from "~icons/ep/close"; + +export function useTags() { + const route = useRoute(); + const router = useRouter(); + const instance = getCurrentInstance(); + const pureSetting = useSettingStoreHook(); + + const buttonTop = ref(0); + const buttonLeft = ref(0); + const translateX = ref(0); + const visible = ref(false); + const activeIndex = ref(-1); + // 褰撳墠鍙抽敭閫変腑鐨勮矾鐢变俊鎭� + const currentSelect = ref({}); + const isScrolling = ref(false); + + /** 鏄剧ず妯″紡锛岄粯璁ょ伒鍔ㄦā寮� */ + const showModel = ref( + storageLocal().getItem<StorageConfigs>( + `${responsiveStorageNameSpace()}configure` + )?.showModel || "smart" + ); + /** 鏄惁闅愯棌鏍囩椤碉紝榛樿鏄剧ず */ + const showTags = + ref( + storageLocal().getItem<StorageConfigs>( + `${responsiveStorageNameSpace()}configure` + ).hideTabs + ) ?? ref("false"); + const multiTags: any = computed(() => { + return useMultiTagsStoreHook().multiTags; + }); + + const tagsViews = reactive<Array<tagsViewsType>>([ + { + icon: RefreshRight, + text: "閲嶆柊鍔犺浇", + divided: false, + disabled: false, + show: true + }, + { + icon: Close, + text: "鍏抽棴褰撳墠鏍囩椤�", + divided: false, + disabled: multiTags.value.length > 1 ? false : true, + show: true + }, + { + icon: CloseLeftTags, + text: "鍏抽棴宸︿晶鏍囩椤�", + divided: true, + disabled: multiTags.value.length > 1 ? false : true, + show: true + }, + { + icon: CloseRightTags, + text: "鍏抽棴鍙充晶鏍囩椤�", + divided: false, + disabled: multiTags.value.length > 1 ? false : true, + show: true + }, + { + icon: CloseOtherTags, + text: "鍏抽棴鍏朵粬鏍囩椤�", + divided: true, + disabled: multiTags.value.length > 2 ? false : true, + show: true + }, + { + icon: CloseAllTags, + text: "鍏抽棴鍏ㄩ儴鏍囩椤�", + divided: false, + disabled: multiTags.value.length > 1 ? false : true, + show: true + }, + { + icon: Fullscreen, + text: "鍐呭鍖哄叏灞�", + divided: true, + disabled: false, + show: true + } + ]); + + function conditionHandle(item, previous, next) { + if (isBoolean(route?.meta?.showLink) && route?.meta?.showLink === false) { + if (Object.keys(route.query).length > 0) { + return isEqual(route.query, item.query) ? previous : next; + } else { + return isEqual(route.params, item.params) ? previous : next; + } + } else { + return route.path === item.path ? previous : next; + } + } + + const isFixedTag = computed(() => { + return item => { + return isBoolean(item?.meta?.fixedTag) && item?.meta?.fixedTag === true; + }; + }); + + const iconIsActive = computed(() => { + return (item, index) => { + if (index === 0) return; + return conditionHandle(item, true, false); + }; + }); + + const linkIsActive = computed(() => { + return item => { + return conditionHandle(item, "is-active", ""); + }; + }); + + const scheduleIsActive = computed(() => { + return item => { + return conditionHandle(item, "schedule-active", ""); + }; + }); + + const getTabStyle = computed((): CSSProperties => { + return { + transform: `translateX(${translateX.value}px)`, + transition: isScrolling.value ? "none" : "transform 0.5s ease-in-out" + }; + }); + + const getContextMenuStyle = computed((): CSSProperties => { + return { left: buttonLeft.value + "px", top: buttonTop.value + "px" }; + }); + + const closeMenu = () => { + visible.value = false; + }; + + /** 榧犳爣绉诲叆娣诲姞婵�娲绘牱寮� */ + function onMouseenter(index) { + if (index) activeIndex.value = index; + if (unref(showModel) === "smart") { + if (hasClass(instance.refs["schedule" + index][0], "schedule-active")) + return; + toggleClass(true, "schedule-in", instance.refs["schedule" + index][0]); + toggleClass(false, "schedule-out", instance.refs["schedule" + index][0]); + } else { + if (hasClass(instance.refs["dynamic" + index][0], "is-active")) return; + toggleClass(true, "card-in", instance.refs["dynamic" + index][0]); + toggleClass(false, "card-out", instance.refs["dynamic" + index][0]); + } + } + + /** 榧犳爣绉诲嚭鎭㈠榛樿鏍峰紡 */ + function onMouseleave(index) { + activeIndex.value = -1; + if (unref(showModel) === "smart") { + if (hasClass(instance.refs["schedule" + index][0], "schedule-active")) + return; + toggleClass(false, "schedule-in", instance.refs["schedule" + index][0]); + toggleClass(true, "schedule-out", instance.refs["schedule" + index][0]); + } else { + if (hasClass(instance.refs["dynamic" + index][0], "is-active")) return; + toggleClass(false, "card-in", instance.refs["dynamic" + index][0]); + toggleClass(true, "card-out", instance.refs["dynamic" + index][0]); + } + } + + function onContentFullScreen() { + pureSetting.hiddenSideBar + ? pureSetting.changeSetting({ key: "hiddenSideBar", value: false }) + : pureSetting.changeSetting({ key: "hiddenSideBar", value: true }); + } + + onMounted(() => { + if (!showModel.value) { + const configure = storageLocal().getItem<StorageConfigs>( + `${responsiveStorageNameSpace()}configure` + ); + configure.showModel = "card"; + storageLocal().setItem( + `${responsiveStorageNameSpace()}configure`, + configure + ); + } + }); + + return { + Close, + route, + router, + visible, + showTags, + instance, + multiTags, + showModel, + tagsViews, + buttonTop, + buttonLeft, + translateX, + isFixedTag, + pureSetting, + activeIndex, + getTabStyle, + isScrolling, + iconIsActive, + linkIsActive, + currentSelect, + scheduleIsActive, + getContextMenuStyle, + closeMenu, + onMounted, + onMouseenter, + onMouseleave, + onContentFullScreen + }; +} diff --git a/src/layout/index.vue b/src/layout/index.vue new file mode 100644 index 0000000..c559d9e --- /dev/null +++ b/src/layout/index.vue @@ -0,0 +1,235 @@ +<script setup lang="ts"> +import "animate.css"; +// 寮曞叆 src/components/ReIcon/src/offlineIcon.ts 鏂囦欢涓墍鏈変娇鐢╝ddIcon娣诲姞杩囩殑鏈湴鍥炬爣 +import "@/components/ReIcon/src/offlineIcon"; +import { setType } from "./types"; +import { useLayout } from "./hooks/useLayout"; +import { useAppStoreHook } from "@/store/modules/app"; +import { useSettingStoreHook } from "@/store/modules/settings"; +import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange"; +import { + h, + ref, + reactive, + computed, + onMounted, + onBeforeMount, + defineComponent +} from "vue"; +import { + useDark, + useGlobal, + deviceDetection, + useResizeObserver +} from "@pureadmin/utils"; + +import LayTag from "./components/lay-tag/index.vue"; +import LayNavbar from "./components/lay-navbar/index.vue"; +import LayContent from "./components/lay-content/index.vue"; +import LaySetting from "./components/lay-setting/index.vue"; +import NavVertical from "./components/lay-sidebar/NavVertical.vue"; +import NavHorizontal from "./components/lay-sidebar/NavHorizontal.vue"; +import BackTopIcon from "@/assets/svg/back_top.svg?component"; + +const appWrapperRef = ref(); +const { isDark } = useDark(); +const { layout } = useLayout(); +const isMobile = deviceDetection(); +const pureSetting = useSettingStoreHook(); +const { $storage } = useGlobal<GlobalPropertiesApi>(); + +const set: setType = reactive({ + sidebar: computed(() => { + return useAppStoreHook().sidebar; + }), + + device: computed(() => { + return useAppStoreHook().device; + }), + + fixedHeader: computed(() => { + return pureSetting.fixedHeader; + }), + + classes: computed(() => { + return { + hideSidebar: !set.sidebar.opened, + openSidebar: set.sidebar.opened, + withoutAnimation: set.sidebar.withoutAnimation, + mobile: set.device === "mobile" + }; + }), + + hideTabs: computed(() => { + return $storage?.configure.hideTabs; + }) +}); + +function setTheme(layoutModel: string) { + window.document.body.setAttribute("layout", layoutModel); + $storage.layout = { + layout: `${layoutModel}`, + theme: $storage.layout?.theme, + darkMode: $storage.layout?.darkMode, + sidebarStatus: $storage.layout?.sidebarStatus, + epThemeColor: $storage.layout?.epThemeColor, + themeColor: $storage.layout?.themeColor, + overallStyle: $storage.layout?.overallStyle + }; +} + +function toggle(device: string, bool: boolean) { + useAppStoreHook().toggleDevice(device); + useAppStoreHook().toggleSideBar(bool, "resize"); +} + +// 鍒ゆ柇鏄惁鍙嚜鍔ㄥ叧闂彍鍗曟爮 +let isAutoCloseSidebar = true; + +useResizeObserver(appWrapperRef, entries => { + if (isMobile) return; + const entry = entries[0]; + const [{ inlineSize: width, blockSize: height }] = entry.borderBoxSize; + useAppStoreHook().setViewportSize({ width, height }); + width <= 760 ? setTheme("vertical") : setTheme(useAppStoreHook().layout); + /** width app-wrapper绫诲鍣ㄥ搴� + * 0 < width <= 760 闅愯棌渚ц竟鏍� + * 760 < width <= 990 鎶樺彔渚ц竟鏍� + * width > 990 灞曞紑渚ц竟鏍� + */ + if (width > 0 && width <= 760) { + toggle("mobile", false); + isAutoCloseSidebar = true; + } else if (width > 760 && width <= 990) { + if (isAutoCloseSidebar) { + toggle("desktop", false); + isAutoCloseSidebar = false; + } + } else if (width > 990 && !set.sidebar.isClickCollapse) { + toggle("desktop", true); + isAutoCloseSidebar = true; + } else { + toggle("desktop", false); + isAutoCloseSidebar = false; + } +}); + +onMounted(() => { + if (isMobile) { + toggle("mobile", false); + } +}); + +onBeforeMount(() => { + useDataThemeChange().dataThemeChange($storage.layout?.overallStyle); +}); + +const LayHeader = defineComponent({ + name: "LayHeader", + render() { + return h( + "div", + { + class: { "fixed-header": set.fixedHeader }, + style: [ + set.hideTabs && layout.value.includes("horizontal") + ? isDark.value + ? "box-shadow: 0 1px 4px #0d0d0d" + : "box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08)" + : "" + ] + }, + { + default: () => [ + !pureSetting.hiddenSideBar && + (layout.value.includes("vertical") || layout.value.includes("mix")) + ? h(LayNavbar) + : null, + !pureSetting.hiddenSideBar && layout.value.includes("horizontal") + ? h(NavHorizontal) + : null, + h(LayTag) + ] + } + ); + } +}); +</script> + +<template> + <div ref="appWrapperRef" :class="['app-wrapper', set.classes]"> + <div + v-show=" + set.device === 'mobile' && + set.sidebar.opened && + layout.includes('vertical') + " + class="app-mask" + @click="useAppStoreHook().toggleSideBar()" + /> + <NavVertical + v-show=" + !pureSetting.hiddenSideBar && + (layout.includes('vertical') || layout.includes('mix')) + " + /> + <div + :class="[ + 'main-container', + pureSetting.hiddenSideBar ? 'main-hidden' : '' + ]" + > + <div v-if="set.fixedHeader"> + <LayHeader /> + <!-- 涓讳綋鍐呭 --> + <LayContent :fixed-header="set.fixedHeader" /> + </div> + <el-scrollbar v-else> + <el-backtop + title="鍥炲埌椤堕儴" + target=".main-container .el-scrollbar__wrap" + > + <BackTopIcon /> + </el-backtop> + <LayHeader /> + <!-- 涓讳綋鍐呭 --> + <LayContent :fixed-header="set.fixedHeader" /> + </el-scrollbar> + </div> + <!-- 绯荤粺璁剧疆 --> + <LaySetting /> + </div> +</template> + +<style lang="scss" scoped> +.app-wrapper { + position: relative; + width: 100%; + height: 100%; + + &::after { + clear: both; + display: table; + content: ""; + } + + &.mobile.openSidebar { + position: fixed; + top: 0; + } +} + +.app-mask { + position: absolute; + top: 0; + z-index: 2001; + width: 100%; + height: 100%; + background: #000; + opacity: 0.3; +} + +.re-screen { + margin-top: 12px; +} +</style> diff --git a/src/layout/redirect.vue b/src/layout/redirect.vue new file mode 100644 index 0000000..6e16339 --- /dev/null +++ b/src/layout/redirect.vue @@ -0,0 +1,24 @@ +<script setup lang="ts"> +import { unref } from "vue"; +import { useRouter } from "vue-router"; + +defineOptions({ + name: "Redirect" +}); + +const { currentRoute, replace } = useRouter(); + +const { params, query } = unref(currentRoute); +const { path } = params; + +const _path = Array.isArray(path) ? path.join("/") : path; + +replace({ + path: "/" + _path, + query +}); +</script> + +<template> + <div /> +</template> diff --git a/src/layout/types.ts b/src/layout/types.ts new file mode 100644 index 0000000..32da0c1 --- /dev/null +++ b/src/layout/types.ts @@ -0,0 +1,92 @@ +import type { FunctionalComponent } from "vue"; +const { VITE_HIDE_HOME } = import.meta.env; + +export const routerArrays: Array<RouteConfigs> = + VITE_HIDE_HOME === "false" + ? [ + { + path: "/welcome", + meta: { + title: "棣栭〉", + icon: "ep/home-filled" + } + } + ] + : []; + +export type routeMetaType = { + title?: string; + icon?: string | FunctionalComponent; + showLink?: boolean; + savedPosition?: boolean; + auths?: Array<string>; +}; + +export type RouteConfigs = { + path?: string; + query?: object; + params?: object; + meta?: routeMetaType; + children?: RouteConfigs[]; + name?: string; +}; + +export type multiTagsType = { + tags: Array<RouteConfigs>; +}; + +export type tagsViewsType = { + icon: string | FunctionalComponent; + text: string; + divided: boolean; + disabled: boolean; + show: boolean; +}; + +export interface setType { + sidebar: { + opened: boolean; + withoutAnimation: boolean; + isClickCollapse: boolean; + }; + device: string; + fixedHeader: boolean; + classes: { + hideSidebar: boolean; + openSidebar: boolean; + withoutAnimation: boolean; + mobile: boolean; + }; + hideTabs: boolean; +} + +export type menuType = { + id?: number; + name?: string; + path?: string; + noShowingChildren?: boolean; + children?: menuType[]; + value: unknown; + meta?: { + icon?: string; + title?: string; + rank?: number; + showParent?: boolean; + extraIcon?: string; + }; + showTooltip?: boolean; + parentId?: number; + pathList?: number[]; + redirect?: string; +}; + +export type themeColorsType = { + color: string; + themeColor: string; +}; + +export interface scrollbarDomType extends HTMLElement { + wrap?: { + offsetWidth: number; + }; +} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..d603e32 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,64 @@ +import App from "./App.vue"; +import router from "./router"; +import { setupStore } from "@/store"; +import { getPlatformConfig } from "./config"; +import { MotionPlugin } from "@vueuse/motion"; +// import { useEcharts } from "@/plugins/echarts"; +import { createApp, type Directive } from "vue"; +import { useElementPlus } from "@/plugins/elementPlus"; +import { injectResponsiveStorage } from "@/utils/responsive"; + +import Table from "@pureadmin/table"; +// import PureDescriptions from "@pureadmin/descriptions"; + +// 寮曞叆閲嶇疆鏍峰紡 +import "./style/reset.scss"; +// 瀵煎叆鍏叡鏍峰紡 +import "./style/index.scss"; +// 涓�瀹氳鍦╩ain.ts涓鍏ailwind.css锛岄槻姝ite姣忔hmr閮戒細璇锋眰src/style/index.scss鏁翠綋css鏂囦欢瀵艰嚧鐑洿鏂版參鐨勯棶棰� +import "./style/tailwind.css"; +import "element-plus/dist/index.css"; +// 瀵煎叆瀛椾綋鍥炬爣 +import "./assets/iconfont/iconfont.js"; +import "./assets/iconfont/iconfont.css"; + +const app = createApp(App); + +// 鑷畾涔夋寚浠� +import * as directives from "@/directives"; +Object.keys(directives).forEach(key => { + app.directive(key, (directives as { [key: string]: Directive })[key]); +}); + +// 鍏ㄥ眬娉ㄥ唽@iconify/vue鍥炬爣搴� +import { + IconifyIconOffline, + IconifyIconOnline, + FontIcon +} from "./components/ReIcon"; +app.component("IconifyIconOffline", IconifyIconOffline); +app.component("IconifyIconOnline", IconifyIconOnline); +app.component("FontIcon", FontIcon); + +// 鍏ㄥ眬娉ㄥ唽鎸夐挳绾у埆鏉冮檺缁勪欢 +import { Auth } from "@/components/ReAuth"; +import { Perms } from "@/components/RePerms"; +app.component("Auth", Auth); +app.component("Perms", Perms); + +// 鍏ㄥ眬娉ㄥ唽vue-tippy +import "tippy.js/dist/tippy.css"; +import "tippy.js/themes/light.css"; +import VueTippy from "vue-tippy"; +app.use(VueTippy); + +getPlatformConfig(app).then(async config => { + setupStore(app); + app.use(router); + await router.isReady(); + injectResponsiveStorage(app, config); + app.use(MotionPlugin).use(useElementPlus).use(Table); + // .use(PureDescriptions) + // .use(useEcharts); + app.mount("#app"); +}); diff --git a/src/plugins/echarts.ts b/src/plugins/echarts.ts new file mode 100644 index 0000000..cb62d96 --- /dev/null +++ b/src/plugins/echarts.ts @@ -0,0 +1,44 @@ +import type { App } from "vue"; +import * as echarts from "echarts/core"; +import { PieChart, BarChart, LineChart } from "echarts/charts"; +import { CanvasRenderer, SVGRenderer } from "echarts/renderers"; +import { + GridComponent, + TitleComponent, + PolarComponent, + LegendComponent, + GraphicComponent, + ToolboxComponent, + TooltipComponent, + DataZoomComponent, + VisualMapComponent +} from "echarts/components"; + +const { use } = echarts; + +use([ + PieChart, + BarChart, + LineChart, + CanvasRenderer, + SVGRenderer, + GridComponent, + TitleComponent, + PolarComponent, + LegendComponent, + GraphicComponent, + ToolboxComponent, + TooltipComponent, + DataZoomComponent, + VisualMapComponent +]); + +/** + * @description 鎸夐渶寮曞叆echarts锛屽叿浣撶湅 https://echarts.apache.org/handbook/zh/basics/import/#%E5%9C%A8-typescript-%E4%B8%AD%E6%8C%89%E9%9C%80%E5%BC%95%E5%85%A5 + * @see 娓╅Θ鎻愮ず锛氬繀椤诲皢 `$echarts` 娣诲姞鍒板叏灞� `globalProperties` 锛屽叿浣撶湅 https://pure-admin-utils.netlify.app/hooks/useECharts/useECharts#%E4%BD%BF%E7%94%A8%E5%89%8D%E6%8F%90 + */ +export function useEcharts(app: App) { + app.config.globalProperties.$echarts = echarts; +} + +export default echarts; diff --git a/src/plugins/elementPlus.ts b/src/plugins/elementPlus.ts new file mode 100644 index 0000000..8363187 --- /dev/null +++ b/src/plugins/elementPlus.ts @@ -0,0 +1,248 @@ +// 鎸夐渶寮曞叆element-plus锛堣鏂规硶绋冲畾涓旀槑纭�傚綋鐒朵篃鏀寔锛歨ttps://element-plus.org/zh-CN/guide/quickstart.html#%E6%8C%89%E9%9C%80%E5%AF%BC%E5%85%A5锛� +import type { App, Component } from "vue"; +import { + /** + * 涓轰簡鏂逛究婕旂ず骞冲彴灏� element-plus 瀵煎嚭鐨勬墍鏈夌粍浠跺紩鍏ワ紝瀹為檯浣跨敤涓鏋滀綘娌$敤鍒板摢涓粍浠讹紝灏嗗叾娉ㄩ噴鎺夊氨琛� + * 瀵煎嚭鏉ユ簮锛歨ttps://github.com/element-plus/element-plus/blob/dev/packages/element-plus/component.ts#L111-L211 + * */ + ElAffix, + ElAlert, + ElAutocomplete, + ElAutoResizer, + ElAvatar, + ElAnchor, + ElAnchorLink, + ElBacktop, + ElBadge, + ElBreadcrumb, + ElBreadcrumbItem, + ElButton, + ElButtonGroup, + ElCalendar, + ElCard, + ElCarousel, + ElCarouselItem, + ElCascader, + ElCascaderPanel, + ElCheckTag, + ElCheckbox, + ElCheckboxButton, + ElCheckboxGroup, + ElCol, + ElCollapse, + ElCollapseItem, + ElCollapseTransition, + ElColorPicker, + ElConfigProvider, + ElContainer, + ElAside, + ElFooter, + ElHeader, + ElMain, + ElDatePicker, + ElDescriptions, + ElDescriptionsItem, + ElDialog, + ElDivider, + ElDrawer, + ElDropdown, + ElDropdownItem, + ElDropdownMenu, + ElEmpty, + ElForm, + ElFormItem, + ElIcon, + ElImage, + ElImageViewer, + ElInput, + ElInputNumber, + ElLink, + ElMenu, + ElMenuItem, + ElMenuItemGroup, + ElSubMenu, + ElPageHeader, + ElPagination, + ElPopconfirm, + ElPopover, + ElPopper, + ElProgress, + ElRadio, + ElRadioButton, + ElRadioGroup, + ElRate, + ElResult, + ElRow, + ElScrollbar, + ElSelect, + ElOption, + ElOptionGroup, + ElSelectV2, + ElSkeleton, + ElSkeletonItem, + ElSlider, + ElSpace, + ElStatistic, + ElCountdown, + ElSteps, + ElStep, + ElSwitch, + ElTable, + ElTableColumn, + ElTableV2, + ElTabs, + ElTabPane, + ElTag, + ElText, + ElTimePicker, + ElTimeSelect, + ElTimeline, + ElTimelineItem, + ElTooltip, + ElTransfer, + ElTree, + ElTreeSelect, + ElTreeV2, + ElUpload, + ElWatermark, + ElTour, + ElTourStep, + ElSegmented, + /** + * 涓轰簡鏂逛究婕旂ず骞冲彴灏� element-plus 瀵煎嚭鐨勬墍鏈夋彃浠跺紩鍏ワ紝瀹為檯浣跨敤涓鏋滀綘娌$敤鍒板摢涓彃浠讹紝灏嗗叾娉ㄩ噴鎺夊氨琛� + * 瀵煎嚭鏉ユ簮锛歨ttps://github.com/element-plus/element-plus/blob/dev/packages/element-plus/plugin.ts#L11-L16 + * */ + ElLoading, // v-loading 鎸囦护 + ElInfiniteScroll, // v-infinite-scroll 鎸囦护 + ElPopoverDirective, // v-popover 鎸囦护 + ElMessage, // $message 鍏ㄥ眬灞炴�у璞lobalProperties + ElMessageBox, // $msgbox銆�$alert銆�$confirm銆�$prompt 鍏ㄥ眬灞炴�у璞lobalProperties + ElNotification // $notify 鍏ㄥ眬灞炴�у璞lobalProperties +} from "element-plus"; + +const components = [ + ElAffix, + ElAlert, + ElAutocomplete, + ElAutoResizer, + ElAvatar, + ElAnchor, + ElAnchorLink, + ElBacktop, + ElBadge, + ElBreadcrumb, + ElBreadcrumbItem, + ElButton, + ElButtonGroup, + ElCalendar, + ElCard, + ElCarousel, + ElCarouselItem, + ElCascader, + ElCascaderPanel, + ElCheckTag, + ElCheckbox, + ElCheckboxButton, + ElCheckboxGroup, + ElCol, + ElCollapse, + ElCollapseItem, + ElCollapseTransition, + ElColorPicker, + ElConfigProvider, + ElContainer, + ElAside, + ElFooter, + ElHeader, + ElMain, + ElDatePicker, + ElDescriptions, + ElDescriptionsItem, + ElDialog, + ElDivider, + ElDrawer, + ElDropdown, + ElDropdownItem, + ElDropdownMenu, + ElEmpty, + ElForm, + ElFormItem, + ElIcon, + ElImage, + ElImageViewer, + ElInput, + ElInputNumber, + ElLink, + ElMenu, + ElMenuItem, + ElMenuItemGroup, + ElSubMenu, + ElPageHeader, + ElPagination, + ElPopconfirm, + ElPopover, + ElPopper, + ElProgress, + ElRadio, + ElRadioButton, + ElRadioGroup, + ElRate, + ElResult, + ElRow, + ElScrollbar, + ElSelect, + ElOption, + ElOptionGroup, + ElSelectV2, + ElSkeleton, + ElSkeletonItem, + ElSlider, + ElSpace, + ElStatistic, + ElCountdown, + ElSteps, + ElStep, + ElSwitch, + ElTable, + ElTableColumn, + ElTableV2, + ElTabs, + ElTabPane, + ElTag, + ElText, + ElTimePicker, + ElTimeSelect, + ElTimeline, + ElTimelineItem, + ElTooltip, + ElTransfer, + ElTree, + ElTreeSelect, + ElTreeV2, + ElUpload, + ElWatermark, + ElTour, + ElTourStep, + ElSegmented +]; + +const plugins = [ + ElLoading, + ElInfiniteScroll, + ElPopoverDirective, + ElMessage, + ElMessageBox, + ElNotification +]; + +/** 鎸夐渶寮曞叆`element-plus` */ +export function useElementPlus(app: App) { + // 鍏ㄥ眬娉ㄥ唽缁勪欢 + components.forEach((component: Component) => { + app.component(component.name, component); + }); + // 鍏ㄥ眬娉ㄥ唽鎻掍欢 + plugins.forEach(plugin => { + app.use(plugin); + }); +} diff --git a/src/router/index.ts b/src/router/index.ts new file mode 100644 index 0000000..af34dfd --- /dev/null +++ b/src/router/index.ts @@ -0,0 +1,211 @@ +// import "@/utils/sso"; +import Cookies from "js-cookie"; +import { getConfig } from "@/config"; +import NProgress from "@/utils/progress"; +import { buildHierarchyTree } from "@/utils/tree"; +import remainingRouter from "./modules/remaining"; +import { useMultiTagsStoreHook } from "@/store/modules/multiTags"; +import { usePermissionStoreHook } from "@/store/modules/permission"; +import { + isUrl, + openLink, + cloneDeep, + isAllEmpty, + storageLocal +} from "@pureadmin/utils"; +import { + ascending, + getTopMenu, + initRouter, + isOneOfArray, + getHistoryMode, + findRouteByPath, + handleAliveRoute, + formatTwoStageRoutes, + formatFlatteningRoutes +} from "./utils"; +import { + type Router, + type RouteRecordRaw, + type RouteComponent, + createRouter +} from "vue-router"; +import { + type DataInfo, + userKey, + removeToken, + multipleTabsKey +} from "@/utils/auth"; + +/** 鑷姩瀵煎叆鍏ㄩ儴闈欐�佽矾鐢憋紝鏃犻渶鍐嶆墜鍔ㄥ紩鍏ワ紒鍖归厤 src/router/modules 鐩綍锛堜换浣曞祵濂楃骇鍒級涓叿鏈� .ts 鎵╁睍鍚嶇殑鎵�鏈夋枃浠讹紝闄や簡 remaining.ts 鏂囦欢 + * 濡備綍鍖归厤鎵�鏈夋枃浠惰鐪嬶細https://github.com/mrmlnc/fast-glob#basic-syntax + * 濡備綍鎺掗櫎鏂囦欢璇风湅锛歨ttps://cn.vitejs.dev/guide/features.html#negative-patterns + */ +const modules: Record<string, any> = import.meta.glob( + ["./modules/**/*.ts", "!./modules/**/remaining.ts"], + { + eager: true + } +); + +/** 鍘熷闈欐�佽矾鐢憋紙鏈仛浠讳綍澶勭悊锛� */ +const routes = []; + +Object.keys(modules).forEach(key => { + routes.push(modules[key].default); +}); + +/** 瀵煎嚭澶勭悊鍚庣殑闈欐�佽矾鐢憋紙涓夌骇鍙婁互涓婄殑璺敱鍏ㄩ儴鎷嶆垚浜岀骇锛� */ +export const constantRoutes: Array<RouteRecordRaw> = formatTwoStageRoutes( + formatFlatteningRoutes(buildHierarchyTree(ascending(routes.flat(Infinity)))) +); + +/** 鍒濆鐨勯潤鎬佽矾鐢憋紝鐢ㄤ簬閫�鍑虹櫥褰曟椂閲嶇疆璺敱 */ +const initConstantRoutes: Array<RouteRecordRaw> = cloneDeep(constantRoutes); + +/** 鐢ㄤ簬娓叉煋鑿滃崟锛屼繚鎸佸師濮嬪眰绾� */ +export const constantMenus: Array<RouteComponent> = ascending( + routes.flat(Infinity) +).concat(...remainingRouter); + +/** 涓嶅弬涓庤彍鍗曠殑璺敱 */ +export const remainingPaths = Object.keys(remainingRouter).map(v => { + return remainingRouter[v].path; +}); + +/** 鍒涘缓璺敱瀹炰緥 */ +export const router: Router = createRouter({ + history: getHistoryMode(import.meta.env.VITE_ROUTER_HISTORY), + routes: constantRoutes.concat(...(remainingRouter as any)), + strict: true, + scrollBehavior(to, from, savedPosition) { + return new Promise(resolve => { + if (savedPosition) { + return savedPosition; + } else { + if (from.meta.saveSrollTop) { + const top: number = + document.documentElement.scrollTop || document.body.scrollTop; + resolve({ left: 0, top }); + } + } + }); + } +}); + +/** 閲嶇疆璺敱 */ +export function resetRouter() { + router.clearRoutes(); + for (const route of initConstantRoutes.concat(...(remainingRouter as any))) { + router.addRoute(route); + } + router.options.routes = formatTwoStageRoutes( + formatFlatteningRoutes(buildHierarchyTree(ascending(routes.flat(Infinity)))) + ); + usePermissionStoreHook().clearAllCachePage(); +} + +/** 璺敱鐧藉悕鍗� */ +const whiteList = ["/login",'/']; + +const { VITE_HIDE_HOME } = import.meta.env; + +router.beforeEach((to: ToRouteType, _from, next) => { + if (to.meta?.keepAlive) { + handleAliveRoute(to, "add"); + // 椤甸潰鏁翠綋鍒锋柊鍜岀偣鍑绘爣绛鹃〉鍒锋柊 + if (_from.name === undefined || _from.name === "Redirect") { + handleAliveRoute(to); + } + } + const userInfo = storageLocal().getItem<DataInfo<number>>(userKey); + NProgress.start(); + const externalLink = isUrl(to?.name as string); + if (!externalLink) { + to.matched.some(item => { + if (!item.meta.title) return ""; + const Title = getConfig().Title; + if (Title) document.title = `${item.meta.title} | ${Title}`; + else document.title = item.meta.title as string; + }); + } + /** 濡傛灉宸茬粡鐧诲綍骞跺瓨鍦ㄧ櫥褰曚俊鎭悗涓嶈兘璺宠浆鍒拌矾鐢辩櫧鍚嶅崟锛岃�屾槸缁х画淇濇寔鍦ㄥ綋鍓嶉〉闈� */ + function toCorrectRoute() { + whiteList.includes(to.fullPath) ? next(_from.fullPath) : next(); + } + if (Cookies.get(multipleTabsKey) && userInfo) { + // 鏃犳潈闄愯烦杞�403椤甸潰 + if (to.meta?.roles && !isOneOfArray(to.meta?.roles, userInfo?.roles)) { + next({ path: "/error/403" }); + } + // 寮�鍚殣钘忛椤靛悗鍦ㄦ祻瑙堝櫒鍦板潃鏍忔墜鍔ㄨ緭鍏ラ椤祑elcome璺敱鍒欒烦杞埌404椤甸潰 + if (VITE_HIDE_HOME === "true" && to.fullPath === "/welcome") { + next({ path: "/error/404" }); + } + if (_from?.name) { + // name涓鸿秴閾炬帴 + if (externalLink) { + openLink(to?.name as string); + NProgress.done(); + } else { + toCorrectRoute(); + } + } else { + // 鍒锋柊 + if ( + usePermissionStoreHook().wholeMenus.length === 0 && + to.path !== "/login" + ) { + initRouter().then((router: Router) => { + if (!useMultiTagsStoreHook().getMultiTagsCache) { + const { path } = to; + const route = findRouteByPath( + path, + router.options.routes[0].children + ); + getTopMenu(true); + // query銆乸arams妯″紡璺敱浼犲弬鏁扮殑鏍囩椤典笉鍦ㄦ澶勫鐞� + if (route && route.meta?.title) { + if (isAllEmpty(route.parentId) && route.meta?.backstage) { + // 姝ゅ涓哄姩鎬侀《绾ц矾鐢憋紙鐩綍锛� + const { path, name, meta } = route.children[0]; + useMultiTagsStoreHook().handleTags("push", { + path, + name, + meta + }); + } else { + const { path, name, meta } = route; + useMultiTagsStoreHook().handleTags("push", { + path, + name, + meta + }); + } + } + } + // 纭繚鍔ㄦ�佽矾鐢卞畬鍏ㄥ姞鍏ヨ矾鐢卞垪琛ㄥ苟涓斾笉褰卞搷闈欐�佽矾鐢憋紙娉ㄦ剰锛氬姩鎬佽矾鐢卞埛鏂版椂router.beforeEach鍙兘浼氳Е鍙戜袱娆★紝绗竴娆¤Е鍙戝姩鎬佽矾鐢辫繕鏈畬鍏ㄦ坊鍔狅紝绗簩娆″姩鎬佽矾鐢辨墠瀹屽叏娣诲姞鍒拌矾鐢卞垪琛紝濡傛灉闇�瑕佸湪router.beforeEach鍋氫竴浜涘垽鏂彲浠ュ湪to.name瀛樺湪鐨勬潯浠朵笅鍘诲垽鏂紝杩欐牱灏卞彧浼氳Е鍙戜竴娆★級 + if (isAllEmpty(to.name)) router.push(to.fullPath); + }); + } + toCorrectRoute(); + } + } else { + if (to.path !== "/login") { + if (whiteList.indexOf(to.path) !== -1) { + next(); + } else { + removeToken(); + next({ path: "/login" }); + } + } else { + next(); + } + } +}); + +router.afterEach(() => { + NProgress.done(); +}); + +export default router; diff --git a/src/router/modules/error.ts b/src/router/modules/error.ts new file mode 100644 index 0000000..2a57a0d --- /dev/null +++ b/src/router/modules/error.ts @@ -0,0 +1,36 @@ +export default { + path: "/error", + redirect: "/error/403", + meta: { + icon: "ri/information-line", + // showLink: false, + title: "寮傚父椤甸潰", + rank: 9 + }, + children: [ + { + path: "/error/403", + name: "403", + component: () => import("@/views/error/403.vue"), + meta: { + title: "403" + } + }, + { + path: "/error/404", + name: "404", + component: () => import("@/views/error/404.vue"), + meta: { + title: "404" + } + }, + { + path: "/error/500", + name: "500", + component: () => import("@/views/error/500.vue"), + meta: { + title: "500" + } + } + ] +} satisfies RouteConfigsTable; diff --git a/src/router/modules/home.ts b/src/router/modules/home.ts new file mode 100644 index 0000000..93f13bc --- /dev/null +++ b/src/router/modules/home.ts @@ -0,0 +1,25 @@ +const { VITE_HIDE_HOME } = import.meta.env; +const Layout = () => import("@/layout/index.vue"); + +export default { + path: "/welcome", + name: "Welcome", + component: Layout, + redirect: "/welcome", + meta: { + icon: "ep/home-filled", + title: "棣栭〉", + rank: 0 + }, + children: [ + { + path: "/welcome", + name: "Welcome", + component: () => import("@/views/welcome/index.vue"), + meta: { + title: "棣栭〉", + showLink: VITE_HIDE_HOME === "true" ? false : true + } + } + ] +} satisfies RouteConfigsTable; diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts new file mode 100644 index 0000000..8b99234 --- /dev/null +++ b/src/router/modules/remaining.ts @@ -0,0 +1,40 @@ +const Layout = () => import("@/layout/index.vue"); + +export default [ + { + path: "/login", + name: "Login", + component: () => import("@/views/login/index.vue"), + meta: { + title: "鐧诲綍", + showLink: false, + rank: 101 + } + }, + { + path: "/", + name: "Home", + component: () => import("@/views/home/index.vue"), + meta: { + title: "棣栭〉", + showLink: false, + rank: 101 + } + }, + { + path: "/redirect", + component: Layout, + meta: { + title: "鍔犺浇涓�...", + showLink: false, + rank: 102 + }, + children: [ + { + path: "/redirect/:path(.*)", + name: "Redirect", + component: () => import("@/layout/redirect.vue") + } + ] + } +] satisfies Array<RouteConfigsTable>; diff --git a/src/router/utils.ts b/src/router/utils.ts new file mode 100644 index 0000000..1e91571 --- /dev/null +++ b/src/router/utils.ts @@ -0,0 +1,410 @@ +import { + type RouterHistory, + type RouteRecordRaw, + type RouteComponent, + createWebHistory, + createWebHashHistory +} from "vue-router"; +import { router } from "./index"; +import { isProxy, toRaw } from "vue"; +import { useTimeoutFn } from "@vueuse/core"; +import { + isString, + cloneDeep, + isAllEmpty, + intersection, + storageLocal, + isIncludeAllChildren +} from "@pureadmin/utils"; +import { getConfig } from "@/config"; +import { buildHierarchyTree } from "@/utils/tree"; +import { userKey, type DataInfo } from "@/utils/auth"; +import { type menuType, routerArrays } from "@/layout/types"; +import { useMultiTagsStoreHook } from "@/store/modules/multiTags"; +import { usePermissionStoreHook } from "@/store/modules/permission"; +const IFrame = () => import("@/layout/frame.vue"); +// https://cn.vitejs.dev/guide/features.html#glob-import +const modulesRoutes = import.meta.glob("/src/views/**/*.{vue,tsx}"); + +// 鍔ㄦ�佽矾鐢� +import { getAsyncRoutes } from "@/api/routes"; + +function handRank(routeInfo: any) { + const { name, path, parentId, meta } = routeInfo; + return isAllEmpty(parentId) + ? isAllEmpty(meta?.rank) || + (meta?.rank === 0 && name !== "Home" && path !== "/") + ? true + : false + : false; +} + +/** 鎸夌収璺敱涓璵eta涓嬬殑rank绛夌骇鍗囧簭鏉ユ帓搴忚矾鐢� */ +function ascending(arr: any[]) { + arr.forEach((v, index) => { + // 褰搑ank涓嶅瓨鍦ㄦ椂锛屾牴鎹『搴忚嚜鍔ㄥ垱寤猴紝棣栭〉璺敱姘歌繙鍦ㄧ涓�浣� + if (handRank(v)) v.meta.rank = index + 2; + }); + return arr.sort( + (a: { meta: { rank: number } }, b: { meta: { rank: number } }) => { + return a?.meta.rank - b?.meta.rank; + } + ); +} + +/** 杩囨护meta涓璼howLink涓篺alse鐨勮彍鍗� */ +function filterTree(data: RouteComponent[]) { + const newTree = cloneDeep(data).filter( + (v: { meta: { showLink: boolean } }) => v.meta?.showLink !== false + ); + newTree.forEach( + (v: { children }) => v.children && (v.children = filterTree(v.children)) + ); + return newTree; +} + +/** 杩囨护children闀垮害涓�0鐨勭殑鐩綍锛屽綋鐩綍涓嬫病鏈夎彍鍗曟椂锛屼細杩囨护姝ょ洰褰曪紝鐩綍娌℃湁璧嬩簣roles鏉冮檺锛屽綋鐩綍涓嬪彧瑕佹湁涓�涓彍鍗曟湁鏄剧ず鏉冮檺锛岄偅涔堟鐩綍灏变細鏄剧ず */ +function filterChildrenTree(data: RouteComponent[]) { + const newTree = cloneDeep(data).filter((v: any) => v?.children?.length !== 0); + newTree.forEach( + (v: { children }) => v.children && (v.children = filterTree(v.children)) + ); + return newTree; +} + +/** 鍒ゆ柇涓や釜鏁扮粍褰兼鏄惁瀛樺湪鐩稿悓鍊� */ +function isOneOfArray(a: Array<string>, b: Array<string>) { + return Array.isArray(a) && Array.isArray(b) + ? intersection(a, b).length > 0 + ? true + : false + : true; +} + +/** 浠巐ocalStorage閲屽彇鍑哄綋鍓嶇櫥褰曠敤鎴风殑瑙掕壊roles锛岃繃婊ゆ棤鏉冮檺鐨勮彍鍗� */ +function filterNoPermissionTree(data: RouteComponent[]) { + const currentRoles = + storageLocal().getItem<DataInfo<number>>(userKey)?.roles ?? []; + const newTree = cloneDeep(data).filter((v: any) => + isOneOfArray(v.meta?.roles, currentRoles) + ); + newTree.forEach( + (v: any) => v.children && (v.children = filterNoPermissionTree(v.children)) + ); + return filterChildrenTree(newTree); +} + +/** 閫氳繃鎸囧畾 `key` 鑾峰彇鐖剁骇璺緞闆嗗悎锛岄粯璁� `key` 涓� `path` */ +function getParentPaths(value: string, routes: RouteRecordRaw[], key = "path") { + // 娣卞害閬嶅巻鏌ユ壘 + function dfs(routes: RouteRecordRaw[], value: string, parents: string[]) { + for (let i = 0; i < routes.length; i++) { + const item = routes[i]; + // 杩斿洖鐖剁骇path + if (item[key] === value) return parents; + // children涓嶅瓨鍦ㄦ垨涓虹┖鍒欎笉閫掑綊 + if (!item.children || !item.children.length) continue; + // 寰�涓嬫煡鎵炬椂灏嗗綋鍓峱ath鍏ユ爤 + parents.push(item.path); + + if (dfs(item.children, value, parents).length) return parents; + // 娣卞害閬嶅巻鏌ユ壘鏈壘鍒版椂褰撳墠path 鍑烘爤 + parents.pop(); + } + // 鏈壘鍒版椂杩斿洖绌烘暟缁� + return []; + } + + return dfs(routes, value, []); +} + +/** 鏌ユ壘瀵瑰簲 `path` 鐨勮矾鐢变俊鎭� */ +function findRouteByPath(path: string, routes: RouteRecordRaw[]) { + let res = routes.find((item: { path: string }) => item.path == path); + if (res) { + return isProxy(res) ? toRaw(res) : res; + } else { + for (let i = 0; i < routes.length; i++) { + if ( + routes[i].children instanceof Array && + routes[i].children.length > 0 + ) { + res = findRouteByPath(path, routes[i].children); + if (res) { + return isProxy(res) ? toRaw(res) : res; + } + } + } + return null; + } +} + +function addPathMatch() { + if (!router.hasRoute("pathMatch")) { + router.addRoute({ + path: "/:pathMatch(.*)", + name: "pathMatch", + redirect: "/error/404" + }); + } +} + +/** 澶勭悊鍔ㄦ�佽矾鐢憋紙鍚庣杩斿洖鐨勮矾鐢憋級 */ +function handleAsyncRoutes(routeList) { + if (routeList.length === 0) { + usePermissionStoreHook().handleWholeMenus(routeList); + } else { + formatFlatteningRoutes(addAsyncRoutes(routeList)).map( + (v: RouteRecordRaw) => { + // 闃叉閲嶅娣诲姞璺敱 + if ( + router.options.routes[0].children.findIndex( + value => value.path === v.path + ) !== -1 + ) { + return; + } else { + // 鍒囪灏嗚矾鐢眕ush鍒皉outes鍚庤繕闇�瑕佷娇鐢╝ddRoute锛岃繖鏍疯矾鐢辨墠鑳芥甯歌烦杞� + router.options.routes[0].children.push(v); + // 鏈�缁堣矾鐢辫繘琛屽崌搴� + ascending(router.options.routes[0].children); + if (!router.hasRoute(v?.name)) router.addRoute(v); + const flattenRouters: any = router + .getRoutes() + .find(n => n.path === "/"); + // 淇濇寔router.options.routes[0].children涓巔ath涓�"/"鐨刢hildren涓�鑷达紝闃叉鏁版嵁涓嶄竴鑷村鑷村紓甯� + flattenRouters.children = router.options.routes[0].children; + router.addRoute(flattenRouters); + } + } + ); + usePermissionStoreHook().handleWholeMenus(routeList); + } + if (!useMultiTagsStoreHook().getMultiTagsCache) { + useMultiTagsStoreHook().handleTags("equal", [ + ...routerArrays, + ...usePermissionStoreHook().flatteningRoutes.filter( + v => v?.meta?.fixedTag + ) + ]); + } + addPathMatch(); +} + +/** 鍒濆鍖栬矾鐢憋紙`new Promise` 鍐欐硶闃叉鍦ㄥ紓姝ヨ姹備腑閫犳垚鏃犻檺寰幆锛�*/ +function initRouter() { + if (getConfig()?.CachingAsyncRoutes) { + // 寮�鍚姩鎬佽矾鐢辩紦瀛樻湰鍦發ocalStorage + const key = "async-routes"; + const asyncRouteList = storageLocal().getItem(key) as any; + if (asyncRouteList && asyncRouteList?.length > 0) { + return new Promise(resolve => { + handleAsyncRoutes(asyncRouteList); + resolve(router); + }); + } else { + return new Promise(resolve => { + getAsyncRoutes().then(({ data }) => { + handleAsyncRoutes(cloneDeep(data)); + storageLocal().setItem(key, data); + resolve(router); + }); + }); + } + } else { + return new Promise(resolve => { + getAsyncRoutes().then(({ data }) => { + handleAsyncRoutes(cloneDeep(data)); + resolve(router); + }); + }); + } +} + +/** + * 灏嗗绾у祵濂楄矾鐢卞鐞嗘垚涓�缁存暟缁� + * @param routesList 浼犲叆璺敱 + * @returns 杩斿洖澶勭悊鍚庣殑涓�缁磋矾鐢� + */ +function formatFlatteningRoutes(routesList: RouteRecordRaw[]) { + if (routesList.length === 0) return routesList; + let hierarchyList = buildHierarchyTree(routesList); + for (let i = 0; i < hierarchyList.length; i++) { + if (hierarchyList[i].children) { + hierarchyList = hierarchyList + .slice(0, i + 1) + .concat(hierarchyList[i].children, hierarchyList.slice(i + 1)); + } + } + return hierarchyList; +} + +/** + * 涓�缁存暟缁勫鐞嗘垚澶氱骇宓屽鏁扮粍锛堜笁绾у強浠ヤ笂鐨勮矾鐢卞叏閮ㄦ媿鎴愪簩绾э紝keep-alive 鍙敮鎸佸埌浜岀骇缂撳瓨锛� + * https://github.com/pure-admin/vue-pure-admin/issues/67 + * @param routesList 澶勭悊鍚庣殑涓�缁磋矾鐢辫彍鍗曟暟缁� + * @returns 杩斿洖灏嗕竴缁存暟缁勯噸鏂板鐞嗘垚瑙勫畾璺敱鐨勬牸寮� + */ +function formatTwoStageRoutes(routesList: RouteRecordRaw[]) { + if (routesList.length === 0) return routesList; + const newRoutesList: RouteRecordRaw[] = []; + routesList.forEach((v: RouteRecordRaw) => { + if (v.path === "/") { + newRoutesList.push({ + component: v.component, + name: v.name, + path: v.path, + redirect: v.redirect, + meta: v.meta, + children: [] + }); + } else { + newRoutesList[0]?.children.push({ ...v }); + } + }); + return newRoutesList; +} + +/** 澶勭悊缂撳瓨璺敱锛堟坊鍔犮�佸垹闄ゃ�佸埛鏂帮級 */ +function handleAliveRoute({ name }: ToRouteType, mode?: string) { + switch (mode) { + case "add": + usePermissionStoreHook().cacheOperate({ + mode: "add", + name + }); + break; + case "delete": + usePermissionStoreHook().cacheOperate({ + mode: "delete", + name + }); + break; + case "refresh": + usePermissionStoreHook().cacheOperate({ + mode: "refresh", + name + }); + break; + default: + usePermissionStoreHook().cacheOperate({ + mode: "delete", + name + }); + useTimeoutFn(() => { + usePermissionStoreHook().cacheOperate({ + mode: "add", + name + }); + }, 100); + } +} + +/** 杩囨护鍚庣浼犳潵鐨勫姩鎬佽矾鐢� 閲嶆柊鐢熸垚瑙勮寖璺敱 */ +function addAsyncRoutes(arrRoutes: Array<RouteRecordRaw>) { + if (!arrRoutes || !arrRoutes.length) return; + const modulesRoutesKeys = Object.keys(modulesRoutes); + arrRoutes.forEach((v: RouteRecordRaw) => { + // 灏哹ackstage灞炴�у姞鍏eta锛屾爣璇嗘璺敱涓哄悗绔繑鍥炶矾鐢� + v.meta.backstage = true; + // 鐖剁骇鐨剅edirect灞炴�у彇鍊硷細濡傛灉瀛愮骇瀛樺湪涓旂埗绾х殑redirect灞炴�т笉瀛樺湪锛岄粯璁ゅ彇绗竴涓瓙绾х殑path锛涘鏋滃瓙绾у瓨鍦ㄤ笖鐖剁骇鐨剅edirect灞炴�у瓨鍦紝鍙栧瓨鍦ㄧ殑redirect灞炴�э紝浼氳鐩栭粯璁ゅ�� + if (v?.children && v.children.length && !v.redirect) + v.redirect = v.children[0].path; + // 鐖剁骇鐨刵ame灞炴�у彇鍊硷細濡傛灉瀛愮骇瀛樺湪涓旂埗绾х殑name灞炴�т笉瀛樺湪锛岄粯璁ゅ彇绗竴涓瓙绾х殑name锛涘鏋滃瓙绾у瓨鍦ㄤ笖鐖剁骇鐨刵ame灞炴�у瓨鍦紝鍙栧瓨鍦ㄧ殑name灞炴�э紝浼氳鐩栭粯璁ゅ�硷紙娉ㄦ剰锛氭祴璇曚腑鍙戠幇鐖剁骇鐨刵ame涓嶈兘鍜屽瓙绾ame閲嶅锛屽鏋滈噸澶嶄細閫犳垚閲嶅畾鍚戞棤鏁堬紙璺宠浆404锛夛紝鎵�浠ヨ繖閲岀粰鐖剁骇鐨刵ame璧峰悕鐨勬椂鍊欏悗闈細鑷姩鍔犱笂`Parent`锛岄伩鍏嶉噸澶嶏級 + if (v?.children && v.children.length && !v.name) + v.name = (v.children[0].name as string) + "Parent"; + if (v.meta?.frameSrc) { + v.component = IFrame; + } else { + // 瀵瑰悗绔紶component缁勪欢璺緞鍜屼笉浼犲仛鍏煎锛堝鏋滃悗绔紶component缁勪欢璺緞锛岄偅涔坧ath鍙互闅忎究鍐欙紝濡傛灉涓嶄紶锛宑omponent缁勪欢璺緞浼氳窡path淇濇寔涓�鑷达級 + const index = v?.component + ? modulesRoutesKeys.findIndex(ev => ev.includes(v.component as any)) + : modulesRoutesKeys.findIndex(ev => ev.includes(v.path)); + v.component = modulesRoutes[modulesRoutesKeys[index]]; + } + if (v?.children && v.children.length) { + addAsyncRoutes(v.children); + } + }); + return arrRoutes; +} + +/** 鑾峰彇璺敱鍘嗗彶妯″紡 https://next.router.vuejs.org/zh/guide/essentials/history-mode.html */ +function getHistoryMode(routerHistory): RouterHistory { + // len涓�1 浠h〃鍙湁鍘嗗彶妯″紡 涓�2 浠h〃鍘嗗彶妯″紡涓瓨鍦╞ase鍙傛暟 https://next.router.vuejs.org/zh/api/#%E5%8F%82%E6%95%B0-1 + const historyMode = routerHistory.split(","); + const leftMode = historyMode[0]; + const rightMode = historyMode[1]; + // no param + if (historyMode.length === 1) { + if (leftMode === "hash") { + return createWebHashHistory(""); + } else if (leftMode === "h5") { + return createWebHistory(""); + } + } //has param + else if (historyMode.length === 2) { + if (leftMode === "hash") { + return createWebHashHistory(rightMode); + } else if (leftMode === "h5") { + return createWebHistory(rightMode); + } + } +} + +/** 鑾峰彇褰撳墠椤甸潰鎸夐挳绾у埆鐨勬潈闄� */ +function getAuths(): Array<string> { + return router.currentRoute.value.meta.auths as Array<string>; +} + +/** 鏄惁鏈夋寜閽骇鍒殑鏉冮檺锛堟牴鎹矾鐢盽meta`涓殑`auths`瀛楁杩涜鍒ゆ柇锛�*/ +function hasAuth(value: string | Array<string>): boolean { + if (!value) return false; + /** 浠庡綋鍓嶈矾鐢辩殑`meta`瀛楁閲岃幏鍙栨寜閽骇鍒殑鎵�鏈夎嚜瀹氫箟`code`鍊� */ + const metaAuths = getAuths(); + if (!metaAuths) return false; + const isAuths = isString(value) + ? metaAuths.includes(value) + : isIncludeAllChildren(value, metaAuths); + return isAuths ? true : false; +} + +function handleTopMenu(route) { + if (route?.children && route.children.length > 1) { + if (route.redirect) { + return route.children.filter(cur => cur.path === route.redirect)[0]; + } else { + return route.children[0]; + } + } else { + return route; + } +} + +/** 鑾峰彇鎵�鏈夎彍鍗曚腑鐨勭涓�涓彍鍗曪紙椤剁骇鑿滃崟锛�*/ +function getTopMenu(tag = false): menuType { + const topMenu = handleTopMenu( + usePermissionStoreHook().wholeMenus[0]?.children[0] + ); + tag && useMultiTagsStoreHook().handleTags("push", topMenu); + return topMenu; +} + +export { + hasAuth, + getAuths, + ascending, + filterTree, + initRouter, + getTopMenu, + addPathMatch, + isOneOfArray, + getHistoryMode, + addAsyncRoutes, + getParentPaths, + findRouteByPath, + handleAliveRoute, + formatTwoStageRoutes, + formatFlatteningRoutes, + filterNoPermissionTree +}; diff --git a/src/store/index.ts b/src/store/index.ts new file mode 100644 index 0000000..a8dc752 --- /dev/null +++ b/src/store/index.ts @@ -0,0 +1,9 @@ +import type { App } from "vue"; +import { createPinia } from "pinia"; +const store = createPinia(); + +export function setupStore(app: App<Element>) { + app.use(store); +} + +export { store }; diff --git a/src/store/modules/app.ts b/src/store/modules/app.ts new file mode 100644 index 0000000..1f5a9a1 --- /dev/null +++ b/src/store/modules/app.ts @@ -0,0 +1,85 @@ +import { defineStore } from "pinia"; +import { + type appType, + store, + getConfig, + storageLocal, + deviceDetection, + responsiveStorageNameSpace +} from "../utils"; + +export const useAppStore = defineStore("pure-app", { + state: (): appType => ({ + sidebar: { + opened: + storageLocal().getItem<StorageConfigs>( + `${responsiveStorageNameSpace()}layout` + )?.sidebarStatus ?? getConfig().SidebarStatus, + withoutAnimation: false, + isClickCollapse: false + }, + // 杩欓噷鐨刲ayout鐢ㄤ簬鐩戝惉瀹瑰櫒鎷栨媺鍚庢仮澶嶅搴旂殑瀵艰埅妯″紡 + layout: + storageLocal().getItem<StorageConfigs>( + `${responsiveStorageNameSpace()}layout` + )?.layout ?? getConfig().Layout, + device: deviceDetection() ? "mobile" : "desktop", + // 娴忚鍣ㄧ獥鍙g殑鍙鍖哄煙澶у皬 + viewportSize: { + width: document.documentElement.clientWidth, + height: document.documentElement.clientHeight + } + }), + getters: { + getSidebarStatus(state) { + return state.sidebar.opened; + }, + getDevice(state) { + return state.device; + }, + getViewportWidth(state) { + return state.viewportSize.width; + }, + getViewportHeight(state) { + return state.viewportSize.height; + } + }, + actions: { + TOGGLE_SIDEBAR(opened?: boolean, resize?: string) { + const layout = storageLocal().getItem<StorageConfigs>( + `${responsiveStorageNameSpace()}layout` + ); + if (opened && resize) { + this.sidebar.withoutAnimation = true; + this.sidebar.opened = true; + layout.sidebarStatus = true; + } else if (!opened && resize) { + this.sidebar.withoutAnimation = true; + this.sidebar.opened = false; + layout.sidebarStatus = false; + } else if (!opened && !resize) { + this.sidebar.withoutAnimation = false; + this.sidebar.opened = !this.sidebar.opened; + this.sidebar.isClickCollapse = !this.sidebar.opened; + layout.sidebarStatus = this.sidebar.opened; + } + storageLocal().setItem(`${responsiveStorageNameSpace()}layout`, layout); + }, + async toggleSideBar(opened?: boolean, resize?: string) { + await this.TOGGLE_SIDEBAR(opened, resize); + }, + toggleDevice(device: string) { + this.device = device; + }, + setLayout(layout) { + this.layout = layout; + }, + setViewportSize(size) { + this.viewportSize = size; + } + } +}); + +export function useAppStoreHook() { + return useAppStore(store); +} diff --git a/src/store/modules/epTheme.ts b/src/store/modules/epTheme.ts new file mode 100644 index 0000000..e6f62d2 --- /dev/null +++ b/src/store/modules/epTheme.ts @@ -0,0 +1,49 @@ +import { defineStore } from "pinia"; +import { + store, + getConfig, + storageLocal, + responsiveStorageNameSpace +} from "../utils"; + +export const useEpThemeStore = defineStore("pure-epTheme", { + state: () => ({ + epThemeColor: + storageLocal().getItem<StorageConfigs>( + `${responsiveStorageNameSpace()}layout` + )?.epThemeColor ?? getConfig().EpThemeColor, + epTheme: + storageLocal().getItem<StorageConfigs>( + `${responsiveStorageNameSpace()}layout` + )?.theme ?? getConfig().Theme + }), + getters: { + getEpThemeColor(state) { + return state.epThemeColor; + }, + /** 鐢ㄤ簬mix瀵艰埅妯″紡涓媓amburger-svg鐨刦ill灞炴�� */ + fill(state) { + if (state.epTheme === "light") { + return "#409eff"; + } else { + return "#fff"; + } + } + }, + actions: { + setEpThemeColor(newColor: string): void { + const layout = storageLocal().getItem<StorageConfigs>( + `${responsiveStorageNameSpace()}layout` + ); + this.epTheme = layout?.theme; + this.epThemeColor = newColor; + if (!layout) return; + layout.epThemeColor = newColor; + storageLocal().setItem(`${responsiveStorageNameSpace()}layout`, layout); + } + } +}); + +export function useEpThemeStoreHook() { + return useEpThemeStore(store); +} diff --git a/src/store/modules/multiTags.ts b/src/store/modules/multiTags.ts new file mode 100644 index 0000000..5d1b669 --- /dev/null +++ b/src/store/modules/multiTags.ts @@ -0,0 +1,145 @@ +import { defineStore } from "pinia"; +import { + type multiType, + type positionType, + store, + isUrl, + isEqual, + isNumber, + isBoolean, + getConfig, + routerArrays, + storageLocal, + responsiveStorageNameSpace +} from "../utils"; +import { usePermissionStoreHook } from "./permission"; + +export const useMultiTagsStore = defineStore("pure-multiTags", { + state: () => ({ + // 瀛樺偍鏍囩椤典俊鎭紙璺敱淇℃伅锛� + multiTags: storageLocal().getItem<StorageConfigs>( + `${responsiveStorageNameSpace()}configure` + )?.multiTagsCache + ? storageLocal().getItem<StorageConfigs>( + `${responsiveStorageNameSpace()}tags` + ) + : ([ + ...routerArrays, + ...usePermissionStoreHook().flatteningRoutes.filter( + v => v?.meta?.fixedTag + ) + ] as any), + multiTagsCache: storageLocal().getItem<StorageConfigs>( + `${responsiveStorageNameSpace()}configure` + )?.multiTagsCache + }), + getters: { + getMultiTagsCache(state) { + return state.multiTagsCache; + } + }, + actions: { + multiTagsCacheChange(multiTagsCache: boolean) { + this.multiTagsCache = multiTagsCache; + if (multiTagsCache) { + storageLocal().setItem( + `${responsiveStorageNameSpace()}tags`, + this.multiTags + ); + } else { + storageLocal().removeItem(`${responsiveStorageNameSpace()}tags`); + } + }, + tagsCache(multiTags) { + this.getMultiTagsCache && + storageLocal().setItem( + `${responsiveStorageNameSpace()}tags`, + multiTags + ); + }, + handleTags<T>( + mode: string, + value?: T | multiType, + position?: positionType + ): T { + switch (mode) { + case "equal": + this.multiTags = value; + this.tagsCache(this.multiTags); + break; + case "push": + { + const tagVal = value as multiType; + // 涓嶆坊鍔犲埌鏍囩椤� + if (tagVal?.meta?.hiddenTag) return; + // 濡傛灉鏄閾炬棤闇�娣诲姞淇℃伅鍒版爣绛鹃〉 + if (isUrl(tagVal?.name)) return; + // 濡傛灉title涓虹┖鎷掔粷娣诲姞绌轰俊鎭埌鏍囩椤� + if (tagVal?.meta?.title.length === 0) return; + // showLink:false 涓嶆坊鍔犲埌鏍囩椤� + if (isBoolean(tagVal?.meta?.showLink) && !tagVal?.meta?.showLink) + return; + const tagPath = tagVal.path; + // 鍒ゆ柇tag鏄惁宸插瓨鍦� + const tagHasExits = this.multiTags.some(tag => { + return tag.path === tagPath; + }); + + // 鍒ゆ柇tag涓殑query閿�兼槸鍚︾浉绛� + const tagQueryHasExits = this.multiTags.some(tag => { + return isEqual(tag?.query, tagVal?.query); + }); + + // 鍒ゆ柇tag涓殑params閿�兼槸鍚︾浉绛� + const tagParamsHasExits = this.multiTags.some(tag => { + return isEqual(tag?.params, tagVal?.params); + }); + + if (tagHasExits && tagQueryHasExits && tagParamsHasExits) return; + + // 鍔ㄦ�佽矾鐢卞彲鎵撳紑鐨勬渶澶ф暟閲� + const dynamicLevel = tagVal?.meta?.dynamicLevel ?? -1; + if (dynamicLevel > 0) { + if ( + this.multiTags.filter(e => e?.path === tagPath).length >= + dynamicLevel + ) { + // 濡傛灉褰撳墠宸叉墦寮�鐨勫姩鎬佽矾鐢辨暟澶т簬dynamicLevel锛屾浛鎹㈢涓�涓姩鎬佽矾鐢辨爣绛� + const index = this.multiTags.findIndex( + item => item?.path === tagPath + ); + index !== -1 && this.multiTags.splice(index, 1); + } + } + this.multiTags.push(value); + this.tagsCache(this.multiTags); + if ( + getConfig()?.MaxTagsLevel && + isNumber(getConfig().MaxTagsLevel) + ) { + if (this.multiTags.length > getConfig().MaxTagsLevel) { + this.multiTags.splice(1, 1); + } + } + } + break; + case "splice": + if (!position) { + const index = this.multiTags.findIndex(v => v.path === value); + if (index === -1) return; + this.multiTags.splice(index, 1); + } else { + this.multiTags.splice(position?.startIndex, position?.length); + } + this.tagsCache(this.multiTags); + return this.multiTags; + case "slice": + return this.multiTags.slice(-1); + } + } + } +}); + +export function useMultiTagsStoreHook() { + return useMultiTagsStore(store); +} diff --git a/src/store/modules/permission.ts b/src/store/modules/permission.ts new file mode 100644 index 0000000..97bc7cd --- /dev/null +++ b/src/store/modules/permission.ts @@ -0,0 +1,74 @@ +import { defineStore } from "pinia"; +import { + type cacheType, + store, + debounce, + ascending, + getKeyList, + filterTree, + constantMenus, + filterNoPermissionTree, + formatFlatteningRoutes +} from "../utils"; +import { useMultiTagsStoreHook } from "./multiTags"; + +export const usePermissionStore = defineStore("pure-permission", { + state: () => ({ + // 闈欐�佽矾鐢辩敓鎴愮殑鑿滃崟 + constantMenus, + // 鏁翠綋璺敱鐢熸垚鐨勮彍鍗曪紙闈欐�併�佸姩鎬侊級 + wholeMenus: [], + // 鏁翠綋璺敱锛堜竴缁存暟缁勬牸寮忥級 + flatteningRoutes: [], + // 缂撳瓨椤甸潰keepAlive + cachePageList: [] + }), + actions: { + /** 缁勮鏁翠綋璺敱鐢熸垚鐨勮彍鍗� */ + handleWholeMenus(routes: any[]) { + this.wholeMenus = filterNoPermissionTree( + filterTree(ascending(this.constantMenus.concat(routes))) + ); + this.flatteningRoutes = formatFlatteningRoutes( + this.constantMenus.concat(routes) as any + ); + }, + cacheOperate({ mode, name }: cacheType) { + const delIndex = this.cachePageList.findIndex(v => v === name); + switch (mode) { + case "refresh": + this.cachePageList = this.cachePageList.filter(v => v !== name); + break; + case "add": + this.cachePageList.push(name); + break; + case "delete": + delIndex !== -1 && this.cachePageList.splice(delIndex, 1); + break; + } + /** 鐩戝惉缂撳瓨椤甸潰鏄惁瀛樺湪浜庢爣绛鹃〉锛屼笉瀛樺湪鍒欏垹闄� */ + debounce(() => { + let cacheLength = this.cachePageList.length; + const nameList = getKeyList(useMultiTagsStoreHook().multiTags, "name"); + while (cacheLength > 0) { + nameList.findIndex(v => v === this.cachePageList[cacheLength - 1]) === + -1 && + this.cachePageList.splice( + this.cachePageList.indexOf(this.cachePageList[cacheLength - 1]), + 1 + ); + cacheLength--; + } + })(); + }, + /** 娓呯┖缂撳瓨椤甸潰 */ + clearAllCachePage() { + this.wholeMenus = []; + this.cachePageList = []; + } + } +}); + +export function usePermissionStoreHook() { + return usePermissionStore(store); +} diff --git a/src/store/modules/settings.ts b/src/store/modules/settings.ts new file mode 100644 index 0000000..05c9807 --- /dev/null +++ b/src/store/modules/settings.ts @@ -0,0 +1,35 @@ +import { defineStore } from "pinia"; +import { type setType, store, getConfig } from "../utils"; + +export const useSettingStore = defineStore("pure-setting", { + state: (): setType => ({ + title: getConfig().Title, + fixedHeader: getConfig().FixedHeader, + hiddenSideBar: getConfig().HiddenSideBar + }), + getters: { + getTitle(state) { + return state.title; + }, + getFixedHeader(state) { + return state.fixedHeader; + }, + getHiddenSideBar(state) { + return state.hiddenSideBar; + } + }, + actions: { + CHANGE_SETTING({ key, value }) { + if (Reflect.has(this, key)) { + this[key] = value; + } + }, + changeSetting(data) { + this.CHANGE_SETTING(data); + } + } +}); + +export function useSettingStoreHook() { + return useSettingStore(store); +} diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts new file mode 100644 index 0000000..09b6642 --- /dev/null +++ b/src/store/modules/user.ts @@ -0,0 +1,109 @@ +import { defineStore } from "pinia"; +import { + type userType, + store, + router, + resetRouter, + routerArrays, + storageLocal +} from "../utils"; +import { + type UserResult, + type RefreshTokenResult, + getLogin, + refreshTokenApi +} from "@/api/user"; +import { useMultiTagsStoreHook } from "./multiTags"; +import { type DataInfo, setToken, removeToken, userKey } from "@/utils/auth"; + +export const useUserStore = defineStore("pure-user", { + state: (): userType => ({ + // 澶村儚 + avatar: storageLocal().getItem<DataInfo<number>>(userKey)?.avatar ?? "", + // 鐢ㄦ埛鍚� + username: storageLocal().getItem<DataInfo<number>>(userKey)?.username ?? "", + // 鏄电О + nickname: storageLocal().getItem<DataInfo<number>>(userKey)?.nickname ?? "", + // 椤甸潰绾у埆鏉冮檺 + roles: storageLocal().getItem<DataInfo<number>>(userKey)?.roles ?? [], + // 鎸夐挳绾у埆鏉冮檺 + permissions: + storageLocal().getItem<DataInfo<number>>(userKey)?.permissions ?? [], + // 鏄惁鍕鹃�変簡鐧诲綍椤电殑鍏嶇櫥褰� + isRemembered: false, + // 鐧诲綍椤电殑鍏嶇櫥褰曞瓨鍌ㄥ嚑澶╋紝榛樿7澶� + loginDay: 7 + }), + actions: { + /** 瀛樺偍澶村儚 */ + SET_AVATAR(avatar: string) { + this.avatar = avatar; + }, + /** 瀛樺偍鐢ㄦ埛鍚� */ + SET_USERNAME(username: string) { + this.username = username; + }, + /** 瀛樺偍鏄电О */ + SET_NICKNAME(nickname: string) { + this.nickname = nickname; + }, + /** 瀛樺偍瑙掕壊 */ + SET_ROLES(roles: Array<string>) { + this.roles = roles; + }, + /** 瀛樺偍鎸夐挳绾у埆鏉冮檺 */ + SET_PERMS(permissions: Array<string>) { + this.permissions = permissions; + }, + /** 瀛樺偍鏄惁鍕鹃�変簡鐧诲綍椤电殑鍏嶇櫥褰� */ + SET_ISREMEMBERED(bool: boolean) { + this.isRemembered = bool; + }, + /** 璁剧疆鐧诲綍椤电殑鍏嶇櫥褰曞瓨鍌ㄥ嚑澶� */ + SET_LOGINDAY(value: number) { + this.loginDay = Number(value); + }, + /** 鐧诲叆 */ + async loginByUsername(data) { + return new Promise<UserResult>((resolve, reject) => { + getLogin(data) + .then(data => { + if (data?.success) setToken(data.data); + resolve(data); + }) + .catch(error => { + reject(error); + }); + }); + }, + /** 鍓嶇鐧诲嚭锛堜笉璋冪敤鎺ュ彛锛� */ + logOut() { + this.username = ""; + this.roles = []; + this.permissions = []; + removeToken(); + useMultiTagsStoreHook().handleTags("equal", [...routerArrays]); + resetRouter(); + router.push("/login"); + }, + /** 鍒锋柊`token` */ + async handRefreshToken(data) { + return new Promise<RefreshTokenResult>((resolve, reject) => { + refreshTokenApi(data) + .then(data => { + if (data) { + setToken(data.data); + resolve(data); + } + }) + .catch(error => { + reject(error); + }); + }); + } + } +}); + +export function useUserStoreHook() { + return useUserStore(store); +} diff --git a/src/store/types.ts b/src/store/types.ts new file mode 100644 index 0000000..c33268a --- /dev/null +++ b/src/store/types.ts @@ -0,0 +1,47 @@ +import type { RouteRecordName } from "vue-router"; + +export type cacheType = { + mode: string; + name?: RouteRecordName; +}; + +export type positionType = { + startIndex?: number; + length?: number; +}; + +export type appType = { + sidebar: { + opened: boolean; + withoutAnimation: boolean; + // 鍒ゆ柇鏄惁鎵嬪姩鐐瑰嚮Collapse + isClickCollapse: boolean; + }; + layout: string; + device: string; + viewportSize: { width: number; height: number }; +}; + +export type multiType = { + path: string; + name: string; + meta: any; + query?: object; + params?: object; +}; + +export type setType = { + title: string; + fixedHeader: boolean; + hiddenSideBar: boolean; +}; + +export type userType = { + avatar?: string; + username?: string; + nickname?: string; + roles?: Array<string>; + permissions?: Array<string>; + isRemembered?: boolean; + loginDay?: number; +}; diff --git a/src/store/utils.ts b/src/store/utils.ts new file mode 100644 index 0000000..5dd8c75 --- /dev/null +++ b/src/store/utils.ts @@ -0,0 +1,28 @@ +export { store } from "@/store"; +export { routerArrays } from "@/layout/types"; +export { router, resetRouter, constantMenus } from "@/router"; +export { getConfig, responsiveStorageNameSpace } from "@/config"; +export { + ascending, + filterTree, + filterNoPermissionTree, + formatFlatteningRoutes +} from "@/router/utils"; +export { + isUrl, + isEqual, + isNumber, + debounce, + isBoolean, + getKeyList, + storageLocal, + deviceDetection +} from "@pureadmin/utils"; +export type { + setType, + appType, + userType, + multiType, + cacheType, + positionType +} from "./types"; diff --git a/src/style/dark.scss b/src/style/dark.scss new file mode 100644 index 0000000..746902f --- /dev/null +++ b/src/style/dark.scss @@ -0,0 +1,182 @@ +@use "element-plus/theme-chalk/src/dark/css-vars.scss" as *; + +/* 鏁翠綋鏆楄壊椋庢牸閫傞厤 */ +html.dark { + $border-style: #303030; + $color-white: #fff; + + /* 鑷畾涔夋繁鑹茶儗鏅鑹� */ + // --el-bg-color: #020409; + + /* 甯哥敤border-color 闇�瑕佹椂鍙彇鐢� */ + --pure-border-color: rgb(253 253 253 / 12%); + + /* switch鍏抽棴鐘舵�佷笅鐨刢olor 闇�瑕佹椂鍙彇鐢� */ + --pure-switch-off-color: #ffffff3f; + + .navbar, + .tags-view, + .contextmenu, + .sidebar-container, + .horizontal-header, + .sidebar-logo-container, + .horizontal-header .el-sub-menu__title, + .horizontal-header .submenu-title-noDropdown { + background: var(--el-bg-color) !important; + } + + .app-main, + .app-main-nofixed-header { + background: #020409 !important; + } + + /* 鏍囩椤� */ + .tags-view { + .arrow-left, + .arrow-right { + border-right: 1px solid $border-style; + box-shadow: none; + } + + .arrow-right { + border-left: 1px solid $border-style; + } + + .scroll-item { + .el-icon-close { + &:hover { + color: rgb(255 255 255 / 85%) !important; + background-color: rgb(255 255 255 / 12%); + } + } + + .chrome-tab { + .tag-title { + color: #666; + } + + &:hover { + .chrome-tab__bg { + color: #333; + } + + .tag-title { + color: #adadad; + } + } + } + } + } + + /* 绯荤粺閰嶇疆闈㈡澘 */ + .right-panel-items { + .el-divider__text { + --el-bg-color: var(--el-bg-color); + } + + .el-divider--horizontal { + border-top: none; + } + } + + .el-card { + --el-card-bg-color: var(--el-bg-color); + } + + .el-backtop { + --el-backtop-bg-color: rgb(72 72 78); + --el-backtop-hover-bg-color: var(--el-color-primary); + + transition: background-color 0.25s cubic-bezier(0.7, 0.3, 0.1, 1); + } + + .el-dropdown-menu__item:not(.is-disabled):hover { + background: transparent; + } + + /* 鍏ㄥ眬瑕嗙洊element-plus鐨別l-dialog銆乪l-drawer銆乪l-message-box銆乪l-notification缁勪欢鍙充笂瑙掑叧闂浘鏍囩殑鏍峰紡锛岃〃鐜版洿椴滄槑 */ + .el-icon { + &.el-dialog__close, + &.el-drawer__close, + &.el-message-box__close, + &.el-notification__closeBtn { + &:hover { + color: rgb(255 255 255 / 85%) !important; + background-color: rgb(255 255 255 / 12%); + + .pure-dialog-svg { + color: rgb(255 255 255 / 85%) !important; + } + } + } + } + + /* 鍏嬮殕骞惰嚜瀹氫箟 ElMessage 鏍峰紡锛屼笉浼氬奖鍝� ElMessage 鍘熸湰鏍峰紡锛屽湪 src/utils/message.ts 涓皟鐢ㄨ嚜瀹氫箟鏍峰紡 ElMessage 鏂规硶鍗冲彲锛屾暣浣撴祬鑹查鏍煎湪 src/style/element-plus.scss 鏂囦欢杩涜浜嗛�傞厤 */ + .pure-message { + background-color: rgb(36 37 37) !important; + background-image: initial !important; + box-shadow: + rgb(13 13 13 / 12%) 0 3px 6px -4px, + rgb(13 13 13 / 8%) 0 6px 16px 0, + rgb(13 13 13 / 5%) 0 9px 28px 8px !important; + + & .el-message__content { + color: $color-white !important; + pointer-events: all !important; + background-image: initial !important; + } + + & .el-message__closeBtn { + &:hover { + color: rgb(255 255 255 / 85%); + background-color: rgb(255 255 255 / 12%); + } + } + } + + /* 鑷畾涔夎彍鍗曟悳绱㈡牱寮� */ + .pure-search-dialog { + .el-dialog__footer { + box-shadow: + 0 -1px 0 0 #555a64, + 0 -3px 6px 0 rgb(69 98 155 / 12%); + } + + .search-footer { + .search-footer-item { + color: rgb(235 235 235 / 60%); + + .icon { + box-shadow: none; + } + } + } + } + + /* ReSegmented 缁勪欢 */ + .pure-segmented { + color: rgb(255 255 255 / 65%); + background-color: #000; + + .pure-segmented-item-selected { + background-color: #1f1f1f; + } + + .pure-segmented-item-disabled { + color: rgb(255 255 255 / 25%); + } + } + + /* 浠� el-scrollbar 婊氬姩鏉℃牱寮� 鏀寔澶у鏁版祻瑙堝櫒锛屽Chrome銆丒dge銆丗irefox銆丼afari绛� */ + .pure-scrollbar { + scrollbar-color: rgb(63 64 66) transparent; + + ::-webkit-scrollbar-thumb { + background-color: rgb(63 64 66); + } + + ::-webkit-scrollbar-thumb:hover { + background: rgb(92 93 96); + } + } +} diff --git a/src/style/element-plus.scss b/src/style/element-plus.scss new file mode 100644 index 0000000..f111d75 --- /dev/null +++ b/src/style/element-plus.scss @@ -0,0 +1,189 @@ +.el-form-item__label { + font-weight: 700; +} + +.el-breadcrumb__inner, +.el-breadcrumb__inner a { + font-weight: 400 !important; +} + +.el-dropdown-menu { + padding: 0 !important; +} + +.is-dark { + z-index: 9999 !important; +} + +/* 閲嶇疆 el-button 涓� icon 鐨� margin */ +.reset-margin [class*="el-icon"] + span { + margin-left: 2px !important; +} + +/* 鑷畾涔� popover 鐨勭被鍚� */ +.pure-popper { + padding: 0 !important; +} + +/* nprogress 閫傞厤 element-plus 鐨勪富棰樿壊 */ +#nprogress { + & .bar { + background-color: var(--el-color-primary) !important; + } + + & .peg { + box-shadow: + 0 0 10px var(--el-color-primary), + 0 0 5px var(--el-color-primary) !important; + } + + & .spinner-icon { + border-top-color: var(--el-color-primary); + border-left-color: var(--el-color-primary); + } +} + +.pure-dialog { + .el-dialog__header.show-close { + padding-right: 16px; + } + + .el-dialog__headerbtn { + top: 16px; + right: 12px; + width: 24px; + height: 24px; + } + + .pure-dialog-svg { + color: var(--el-color-info); + } + + .el-dialog__footer { + padding-top: 0; + } +} + +/* 鍏ㄥ眬瑕嗙洊element-plus鐨別l-tour銆乪l-dialog銆乪l-drawer銆乪l-message-box銆乪l-notification缁勪欢鍙充笂瑙掑叧闂浘鏍囧拰el-upload涓婁紶鏂囦欢鍒楄〃鍙充晶鍏抽棴鍥炬爣鐨勬牱寮忥紝琛ㄧ幇鏇撮矞鏄� */ +.el-dialog__headerbtn, +.el-message-box__headerbtn { + &:hover { + .el-dialog__close { + color: var(--el-color-info) !important; + } + } +} + +.el-icon { + &.el-tour__close, + &.el-dialog__close, + &.el-drawer__close, + &.el-message-box__close, + &.el-notification__closeBtn, + .el-upload-list__item.is-ready &.el-icon--close { + width: 24px; + height: 24px; + outline: none; + border-radius: 4px; + transition: + background-color 0.2s, + color 0.2s; + + &:hover { + color: rgb(0 0 0 / 88%) !important; + text-decoration: none; + background-color: rgb(0 0 0 / 6%); + + .pure-dialog-svg { + color: rgb(0 0 0 / 88%) !important; + } + } + } +} + +/* 鍏嬮殕骞惰嚜瀹氫箟 ElMessage 鏍峰紡锛屼笉浼氬奖鍝� ElMessage 鍘熸湰鏍峰紡锛屽湪 src/utils/message.ts 涓皟鐢ㄨ嚜瀹氫箟鏍峰紡 ElMessage 鏂规硶鍗冲彲锛屾暣浣撴殫鑹查鏍煎湪 src/style/dark.scss 鏂囦欢杩涜浜嗛�傞厤 */ +.pure-message { + background: #fff !important; + border-width: 0 !important; + box-shadow: + 0 3px 6px -4px #0000001f, + 0 6px 16px #00000014, + 0 9px 28px 8px #0000000d !important; + + & .el-message__content { + color: #000000d9 !important; + pointer-events: all !important; + background-image: initial !important; + } + + & .el-message__closeBtn { + outline: none; + border-radius: 4px; + transition: + background-color 0.2s, + color 0.2s; + + &:hover { + background-color: rgb(0 0 0 / 6%); + } + } +} + +/* 鑷畾涔夎彍鍗曟悳绱㈡牱寮� */ +.pure-search-dialog { + @media screen and (width > 760px) and (width <= 940px) { + .el-input__inner { + font-size: 12px; + } + } + + @media screen and (width <= 470px) { + .el-input__inner { + font-size: 12px; + } + } + + .el-dialog__header { + display: none; + } + + .el-input__inner { + font-size: 1.2em; + } + + .el-dialog__footer { + width: calc(100% + 32px); + padding: 10px 20px; + margin: auto -16px -16px; + box-shadow: + 0 -1px 0 0 #e0e3e8, + 0 -3px 6px 0 rgb(69 98 155 / 12%); + } +} + +/* 浠� el-scrollbar 婊氬姩鏉℃牱寮忥紝鏀寔澶у鏁版祻瑙堝櫒锛屽Chrome銆丒dge銆丗irefox銆丼afari绛夈�傛暣浣撴殫鑹查鏍煎湪 src/style/dark.scss 鏂囦欢杩涜浜嗛�傞厤 */ +.pure-scrollbar { + scrollbar-color: rgb(221 222 224) transparent; /* 婊戝潡棰滆壊銆佽建閬撻鑹� */ + + /* Firefox */ + scrollbar-width: thin; /* 鍙�夊�间负 'auto', 'thin', 'none' */ + ::-webkit-scrollbar { + width: 6px; /* 婊氬姩鏉″搴� */ + } + + /* 婊氬姩鏉¤建閬� */ + ::-webkit-scrollbar-track { + background: transparent; /* 杞ㄩ亾棰滆壊 */ + } + + /* 婊氬姩鏉℃粦鍧� */ + ::-webkit-scrollbar-thumb { + background-color: rgb(221 222 224); + border-radius: 4px; + } + + /* 婊氬姩鏉℃粦鍧楋細hover鐘舵�� */ + ::-webkit-scrollbar-thumb:hover { + background: rgb(199 201 203); /* 婊戝潡hover棰滆壊 */ + } +} diff --git a/src/style/index.scss b/src/style/index.scss new file mode 100644 index 0000000..aac8c32 --- /dev/null +++ b/src/style/index.scss @@ -0,0 +1,37 @@ +@use "theme"; +@use "transition"; +@use "element-plus"; +@use "sidebar"; +@use "dark"; + +/* 鑷畾涔夊叏灞� CssVar */ +:root { + /* 宸︿晶鑿滃崟灞曞紑銆佹敹璧峰姩鐢绘椂闀� */ + --pure-transition-duration: 0.3s; + + /* 甯哥敤border-color 闇�瑕佹椂鍙彇鐢� */ + --pure-border-color: rgb(5 5 5 / 6%); + + /* switch鍏抽棴鐘舵�佷笅鐨刢olor 闇�瑕佹椂鍙彇鐢� */ + --pure-switch-off-color: #a6a6a6; + + /** 涓婚鑹� */ + --pure-theme-sub-menu-active-text: initial; + --pure-theme-menu-bg: none; + --pure-theme-menu-hover: none; + --pure-theme-sub-menu-bg: transparent; + --pure-theme-menu-text: initial; + --pure-theme-sidebar-logo: none; + --pure-theme-menu-title-hover: initial; + --pure-theme-menu-active-before: transparent; +} + +/* 鐏拌壊妯″紡 */ +.html-grey { + filter: grayscale(100%); +} + +/* 鑹插急妯″紡 */ +.html-weakness { + filter: invert(80%); +} diff --git a/src/style/login.css b/src/style/login.css new file mode 100644 index 0000000..3e0a8ab --- /dev/null +++ b/src/style/login.css @@ -0,0 +1,96 @@ +.wave { + position: fixed; + height: 100%; + width: 80%; + left: 0; + bottom: 0; + z-index: -1; +} + +.login-container { + width: 100vw; + height: 100vh; + max-width: 100%; + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-gap: 18rem; + padding: 0 2rem; +} + +.img { + display: flex; + justify-content: flex-end; + align-items: center; +} + +.img img { + width: 500px; +} + +.login-box { + display: flex; + align-items: center; + text-align: center; + overflow: hidden; +} + +.login-form { + width: 360px; +} + +.avatar { + width: 350px; + height: 80px; +} + +.login-form h2 { + text-transform: uppercase; + margin: 15px 0; + color: #999; + font: + bold 200% Consolas, + Monaco, + monospace; +} + +@media screen and (max-width: 1180px) { + .login-container { + grid-gap: 9rem; + } + + .login-form { + width: 290px; + } + + .login-form h2 { + font-size: 2.4rem; + margin: 8px 0; + } + + .img img { + width: 360px; + } + + .avatar { + width: 280px; + height: 80px; + } +} + +@media screen and (max-width: 968px) { + .wave { + display: none; + } + + .img { + display: none; + } + + .login-container { + grid-template-columns: 1fr; + } + + .login-box { + justify-content: center; + } +} diff --git a/src/style/reset.scss b/src/style/reset.scss new file mode 100644 index 0000000..07fdfb8 --- /dev/null +++ b/src/style/reset.scss @@ -0,0 +1,250 @@ +#app { + width: 100%; + height: 100%; +} + +html { + box-sizing: border-box; + width: 100%; + height: 100%; + line-height: 1.5; + tab-size: 4; + text-size-adjust: 100%; +} + +body { + width: 100%; + height: 100%; + margin: 0; + font-family: + "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", + "Microsoft YaHei", "寰蒋闆呴粦", Arial, sans-serif; + line-height: inherit; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + text-rendering: optimizelegibility; +} + +hr { + height: 0; + color: inherit; + border-top-width: 1px; +} + +abbr:where([title]) { + text-decoration: underline dotted; +} + +a { + color: inherit; + text-decoration: inherit; +} + +b, +strong { + font-weight: bolder; +} + +code, +kbd, +samp, +pre { + font-family: + ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", + "Courier New", monospace; + font-size: 1em; +} + +small { + font-size: 80%; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +table { + text-indent: 0; + border-collapse: collapse; + border-color: inherit; +} + +button, +input, +optgroup, +select, +textarea { + padding: 0; + margin: 0; + font-family: inherit; + font-size: 100%; + line-height: inherit; + color: inherit; +} + +button, +select { + text-transform: none; +} + +button, +[type="button"], +[type="reset"], +[type="submit"] { + background-image: none; +} + +:-moz-focusring { + outline: auto; +} + +:-moz-ui-invalid { + box-shadow: none; +} + +progress { + vertical-align: baseline; +} + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +[type="search"] { + outline-offset: -2px; +} + +::-webkit-file-upload-button { + font: inherit; +} + +summary { + display: list-item; +} + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + padding: 0; + margin: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + padding: 0; + margin: 0; + list-style: none; +} + +textarea { + resize: vertical; +} + +input::placeholder, +textarea::placeholder { + color: #9ca3af; + opacity: 1; +} + +button, +[role="button"] { + cursor: pointer; +} + +:disabled { + cursor: default; +} + +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; +} + +img, +video { + max-width: 100%; + height: auto; +} + +[hidden] { + display: none; +} + +.dark { + color-scheme: dark; +} + +label { + font-weight: 700; +} + +*, +*::before, +*::after { + box-sizing: inherit; +} + +a:focus, +a:active { + outline: none; +} + +a, +a:focus, +a:hover { + color: inherit; + text-decoration: none; + cursor: pointer; +} + +div:focus { + outline: none; +} + +.clearfix { + &::after { + display: block; + height: 0; + clear: both; + font-size: 0; + visibility: hidden; + content: " "; + } +} diff --git a/src/style/sidebar.scss b/src/style/sidebar.scss new file mode 100644 index 0000000..3f1ef28 --- /dev/null +++ b/src/style/sidebar.scss @@ -0,0 +1,719 @@ +/* $sideBarWidth: vertical 妯″紡涓嬩富浣撳唴瀹硅窛绂荤綉椤垫枃妗e乏渚х殑璺濈 */ +@mixin merge-style($sideBarWidth) { + @media screen and (width >= 150px) and (width <= 420px) { + .app-main-nofixed-header { + overflow-y: hidden; + } + } + + @media screen and (width >= 420px) { + .app-main-nofixed-header { + overflow: hidden; + } + } + + /* 淇 windows 涓嬪弻婊氬姩鏉¢棶棰� https://github.com/pure-admin/vue-pure-admin/pull/936#issuecomment-1968125992 */ + .el-popper.pure-scrollbar { + overflow: hidden; + } + + /* popper menu 瓒呭嚭鍐呭鍖哄彲婊氬姩 */ + .pure-scrollbar { + max-height: calc(100vh - calc(50px * 2.5)); + overflow: hidden auto; + } + + .sub-menu-icon { + margin-right: 5px; + font-size: 18px; + + svg { + width: 18px; + height: 18px; + } + } + + .set-icon, + .fullscreen-icon { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 48px; + cursor: pointer; + } + + .main-container { + position: relative; + height: 100vh; + min-height: 100%; + margin-left: $sideBarWidth; + background: #f0f2f5; + + /* main-content 灞炴�у姩鐢� */ + transition: margin-left var(--pure-transition-duration); + + .el-scrollbar__wrap { + height: 100%; + overflow: auto; + } + } + + .fixed-header { + position: fixed; + top: 0; + right: 0; + z-index: 998; + width: calc(100% - #{$sideBarWidth}); + + /* fixed-header 灞炴�у乏涓婅鍔ㄧ敾 */ + transition: width var(--pure-transition-duration); + } + + .main-hidden { + margin-left: 0 !important; + + .fixed-header { + width: 100% !important; + + + .app-main { + padding-top: 37px !important; + } + } + } + + .sidebar-container { + position: fixed; + top: 0; + bottom: 0; + left: 0; + z-index: 1001; + width: $sideBarWidth !important; + height: 100%; + overflow: visible; + font-size: 0; + background: var(--pure-theme-menu-bg) !important; + border-right: 1px solid var(--pure-border-color); + + /* 灞曞紑鍔ㄧ敾 */ + transition: width var(--pure-transition-duration); + + .scrollbar-wrapper { + overflow-x: hidden !important; + } + + .el-scrollbar__bar.is-vertical { + right: 0; + } + + &.has-logo { + .el-scrollbar.pc { + /* logo: 48px銆乴eftCollapse: 40px銆乴eftCollapse-shadow: 4px */ + height: calc(100% - 92px); + } + + /* logo: 48px */ + .el-scrollbar.mobile { + height: calc(100% - 48px); + } + } + + &.no-logo { + .el-scrollbar.pc { + /* leftCollapse: 40px銆乴eftCollapse-shadow: 4px */ + height: calc(100% - 44px); + } + + .el-scrollbar.mobile { + height: 100%; + } + } + + .is-horizontal { + display: none; + } + + a { + display: flex; + flex-wrap: wrap; + width: 100%; + } + + .el-menu { + height: 100%; + background-color: transparent !important; + border: none; + } + + .el-menu-item, + .el-sub-menu__title { + height: 50px; + color: var(--pure-theme-menu-text); + background-color: transparent !important; + + &:hover { + color: var(--pure-theme-menu-title-hover) !important; + } + + div, + span { + height: 50px; + line-height: 50px; + } + } + + .submenu-title-noDropdown, + .el-sub-menu__title { + &:hover { + background-color: transparent; + } + } + + .is-active > .el-sub-menu__title, + .is-active.submenu-title-noDropdown { + color: var(--pure-theme-sub-menu-active-text) !important; + + i { + color: var(--pure-theme-sub-menu-active-text) !important; + } + } + + .is-active { + color: var(--pure-theme-sub-menu-active-text) !important; + transition: color 0.3s; + } + + .el-menu-item.is-active.nest-menu > * { + z-index: 1; + color: #fff; + } + + .el-menu-item.is-active.nest-menu::before { + position: absolute; + inset: 0 8px; + clear: both; + margin: 4px 0; + content: ""; + background: var(--el-color-primary) !important; + border-radius: 3px; + } + + .el-menu .el-menu--inline .el-sub-menu__title, + & .el-sub-menu .el-menu-item { + min-width: $sideBarWidth !important; + font-size: 14px; + background-color: var(--pure-theme-sub-menu-bg) !important; + } + + /* 鏈夊瓙闆嗙殑婵�娲昏彍鍗曞乏渚у皬绔栨潯 */ + .el-menu--collapse + .is-active.outer-most.el-sub-menu + > .el-sub-menu__title::before { + position: absolute; + top: 0; + left: 0; + clear: both; + width: 2px; + height: 100%; + content: ""; + background-color: var(--pure-theme-menu-active-before); + transform: translateY(0); + transition: all var(--pure-transition-duration) ease-in-out; + } + + .el-menu--collapse .outer-most.el-sub-menu > .el-sub-menu__title::before { + position: absolute; + top: 50%; + display: block; + width: 3px; + height: 0; + content: ""; + transform: translateY(-50%); + } + + /* 鏃犲瓙闆嗙殑婵�娲昏彍鍗曡儗鏅� */ + .is-active.submenu-title-noDropdown.outer-most > * { + z-index: 1; + color: #fff; + } + + .is-active.submenu-title-noDropdown.outer-most::before { + position: absolute; + inset: 0 8px; + clear: both; + margin: 4px 0; + content: ""; + background: var(--el-color-primary) !important; + border-radius: 3px; + } + } + + /* vertical 鑿滃崟鎶樺彔 */ + .el-menu--vertical { + .el-menu--popup { + background-color: var(--pure-theme-sub-menu-bg) !important; + + .el-menu-item { + span { + font-size: 14px; + } + } + } + + & > .el-menu { + i, + svg { + margin-right: 5px; + } + } + + .is-active > .el-sub-menu__title, + .is-active.submenu-title-noDropdown { + color: var(--pure-theme-sub-menu-active-text) !important; + + i { + color: var(--pure-theme-sub-menu-active-text) !important; + } + } + + /* 瀛愯彍鍗曚腑杩樻湁瀛愯彍鍗� */ + .el-menu .el-sub-menu__title { + min-width: $sideBarWidth !important; + font-size: 14px; + background-color: var(--pure-theme-sub-menu-bg) !important; + } + + .el-menu-item, + .el-sub-menu__title { + height: 50px; + line-height: 50px; + color: var(--pure-theme-menu-text); + background-color: var(--pure-theme-sub-menu-bg); + + &:hover { + color: var(--pure-theme-menu-title-hover) !important; + } + } + + .is-active { + color: var(--pure-theme-sub-menu-active-text) !important; + transition: color 0.3s; + } + + .el-menu-item.is-active.nest-menu > * { + z-index: 1; + color: #fff; + } + + .el-menu-item.is-active.nest-menu::before { + position: absolute; + inset: 0 8px; + clear: both; + content: ""; + background: var(--el-color-primary) !important; + border-radius: 3px; + } + + .el-menu-item, + .el-sub-menu { + .iconfont { + font-size: 18px; + } + + .el-menu-tooltip__trigger { + width: 54px; + padding: 0; + } + } + } + + /* horizontal 鑿滃崟 */ + .el-menu--horizontal { + & > .el-sub-menu .el-sub-menu__icon-arrow { + position: static !important; + margin-top: 0; + } + + /* 鏃犲瓙鑿滃崟鏃舵縺娲� border-bottom */ + a > .is-active.submenu-title-noDropdown { + border-bottom: 2px solid var(--el-menu-active-color); + } + + .el-menu--popup { + background-color: var(--pure-theme-sub-menu-bg) !important; + + a > .is-active.submenu-title-noDropdown { + border-bottom: none; + } + + .el-menu-item { + color: var(--pure-theme-menu-text); + background-color: var(--pure-theme-sub-menu-bg); + + span { + font-size: 14px; + } + } + + .el-sub-menu__title { + color: var(--pure-theme-menu-text); + } + } + + /* 瀛愯彍鍗曚腑杩樻湁瀛愯彍鍗� */ + .el-menu .el-sub-menu__title { + min-width: $sideBarWidth !important; + font-size: 14px; + background-color: var(--pure-theme-sub-menu-bg) !important; + + &:hover { + color: var(--pure-theme-menu-title-hover) !important; + } + } + + .is-active > .el-sub-menu__title, + .is-active.submenu-title-noDropdown { + color: var(--pure-theme-sub-menu-active-text) !important; + + i { + color: var(--pure-theme-sub-menu-active-text) !important; + } + } + + .nest-menu .el-sub-menu > .el-sub-menu__title, + .el-menu-item { + &:hover { + color: var(--pure-theme-menu-title-hover) !important; + } + } + + .el-menu-item.is-active { + color: var(--pure-theme-sub-menu-active-text) !important; + transition: color 0.3s; + } + + .el-menu-item.is-active.nest-menu > * { + z-index: 1; + color: #fff; + } + + .el-menu-item.is-active.nest-menu::before { + position: absolute; + inset: 0 5px; + clear: both; + content: ""; + background: var(--el-color-primary) !important; + border-radius: 3px; + } + } + + .horizontal-header { + display: flex; + align-items: center; + justify-content: space-around; + width: 100%; + height: 48px; + background: var(--pure-theme-menu-bg) !important; + + .horizontal-header-left { + display: flex; + align-items: center; + width: auto; + min-width: 200px; + height: 100%; + padding-left: 10px; + cursor: pointer; + transition: all var(--pure-transition-duration) ease; + + img { + display: inline-block; + height: 32px; + } + + span { + display: inline-block; + height: 32px; + margin: 2px 0 0 12px; + overflow: hidden; + text-overflow: ellipsis; + font-size: 18px; + font-weight: 600; + line-height: 32px; + color: var(--pure-theme-sub-menu-active-text); + white-space: nowrap; + } + } + + .horizontal-header-menu { + flex: 1; + align-items: center; + min-width: 0; + height: 100%; + } + + .horizontal-header-right { + display: flex; + align-items: center; + justify-content: flex-end; + min-width: 340px; + color: var(--pure-theme-sub-menu-active-text); + + /* 鎼滅储 */ + .search-container, + /* 鍏ㄥ睆 */ + .fullscreen-icon, + /* 娑堟伅閫氱煡 */ + .dropdown-badge, + /* 鐢ㄦ埛鍚� */ + .el-dropdown-link, + /* 璁剧疆 */ + .set-icon { + &:hover { + background: var(--pure-theme-menu-hover); + } + } + + .dropdown-badge { + height: 48px; + color: var(--pure-theme-sub-menu-active-text); + } + + .el-dropdown-link { + display: flex; + align-items: center; + justify-content: space-around; + height: 48px; + padding: 10px; + color: var(--pure-theme-sub-menu-active-text); + cursor: pointer; + + p { + font-size: 14px; + } + + img { + width: 22px; + height: 22px; + border-radius: 50%; + } + } + } + + .el-menu { + width: 100% !important; + height: 100%; + background-color: transparent; + border: none; + } + + .el-menu-item, + .el-sub-menu__title { + padding-right: var(--el-menu-base-level-padding); + color: var(--pure-theme-menu-text); + + &:hover { + color: var(--pure-theme-menu-title-hover) !important; + } + } + + .submenu-title-noDropdown, + .el-sub-menu__title { + height: 48px; + line-height: 48px; + background: var(--pure-theme-menu-bg) !important; + + svg { + position: static !important; + } + } + + .is-active > .el-sub-menu__title, + .is-active.submenu-title-noDropdown { + color: var(--pure-theme-sub-menu-active-text) !important; + + i { + color: var(--pure-theme-sub-menu-active-text) !important; + } + } + + .is-active { + color: var(--pure-theme-sub-menu-active-text) !important; + transition: color 0.3s; + } + } + + .el-menu--collapse .el-menu .el-sub-menu { + min-width: $sideBarWidth !important; + } + + /* 鎵嬫満绔� */ + .mobile { + .fixed-header { + width: 100% !important; + transition: width var(--pure-transition-duration); + } + + .main-container { + margin-left: 0 !important; + } + + .sidebar-container { + z-index: 2001; + width: $sideBarWidth; + transition: transform var(--pure-transition-duration); + } + + &.hideSidebar { + .sidebar-container { + pointer-events: none; + transform: translate3d(-$sideBarWidth, 0, 0); + transition-duration: 0.3s; + } + } + } +} + +body[layout="vertical"] { + $sideBarWidth: 210px; + + @include merge-style($sideBarWidth); + + .el-menu--collapse { + width: 54px; + } + + .sidebar-logo-container { + background: var(--pure-theme-sidebar-logo); + } + + .hideSidebar { + .fixed-header { + width: calc(100% - 54px); + transition: width var(--pure-transition-duration); + } + + .sidebar-container { + width: 54px !important; + transition: width var(--pure-transition-duration); + + .is-active.submenu-title-noDropdown.outer-most { + background: transparent !important; + } + } + + .main-container { + margin-left: 54px; + } + + /* 鑿滃崟鎶樺彔 */ + .el-menu--collapse { + .el-sub-menu { + & > .el-sub-menu__title { + & > span { + visibility: visible; + width: 100%; + height: 100%; + text-align: center; + } + } + } + + .submenu-title-noDropdown { + background: transparent !important; + } + + .el-sub-menu__title { + padding: 0; + } + } + + .sub-menu-icon { + margin-right: 0; + } + } + + /* 鎼滅储 */ + .search-container, + /* 鍏ㄥ睆 */ + .fullscreen-icon, + /* 娑堟伅閫氱煡 */ + .dropdown-badge, + /* 鐢ㄦ埛鍚� */ + .el-dropdown-link, + /* 璁剧疆 */ + .set-icon { + &:hover { + background: #f6f6f6; + } + } +} + +body[layout="horizontal"] { + $sideBarWidth: 0; + + @include merge-style($sideBarWidth); + + .el-menu { + --el-menu-hover-text-color: var(--pure-theme-menu-text) !important; + } + + .fixed-header, + .main-container { + transition: none !important; + } + + .fixed-header { + width: 100%; + } +} + +body[layout="mix"] { + $sideBarWidth: 210px; + + @include merge-style($sideBarWidth); + + .el-menu--collapse { + width: 54px; + } + + .el-menu { + --el-menu-hover-bg-color: transparent !important; + --el-menu-hover-text-color: var(--pure-theme-menu-text) !important; + } + + .hideSidebar { + .fixed-header { + width: calc(100% - 54px); + transition: width var(--pure-transition-duration); + } + + .sidebar-container { + width: 54px !important; + transition: width var(--pure-transition-duration); + + .is-active.submenu-title-noDropdown.outer-most { + background: transparent !important; + } + } + + .main-container { + margin-left: 54px; + } + + /* 鑿滃崟鎶樺彔 */ + .el-menu--collapse { + .el-sub-menu { + & > .el-sub-menu__title { + padding: 0; + + & > span { + visibility: visible; + width: 100%; + height: 100%; + text-align: center; + } + } + } + } + } +} diff --git a/src/style/tailwind.css b/src/style/tailwind.css new file mode 100644 index 0000000..e495ae2 --- /dev/null +++ b/src/style/tailwind.css @@ -0,0 +1,46 @@ +@layer theme, base, components, utilities; +@import "tailwindcss/theme.css" layer(theme); +@import "tailwindcss/utilities.css" layer(utilities); + +@custom-variant dark (&:is(.dark *)); + +@theme { + --color-bg_color: var(--el-bg-color); + --color-primary: var(--el-color-primary); + --color-text_color_primary: var(--el-text-color-primary); + --color-text_color_regular: var(--el-text-color-regular); +} + +/* + The default border color has changed to `currentColor` in Tailwind CSS v4, + so we've added these compatibility styles to make sure everything still + looks the same as it did with Tailwind CSS v3. + + If we ever want to remove these styles, we need to add an explicit border + color utility to any element that depends on these defaults. +*/ +@layer base { + *, + ::after, + ::before, + ::backdrop, + ::file-selector-button { + border-color: var(--color-gray-200, currentColor); + } +} + +@utility flex-c { + @apply flex justify-center items-center; +} + +@utility flex-ac { + @apply flex justify-around items-center; +} + +@utility flex-bc { + @apply flex justify-between items-center; +} + +@utility navbar-bg-hover { + @apply dark:text-white dark:hover:bg-[#242424]!; +} diff --git a/src/style/theme.scss b/src/style/theme.scss new file mode 100644 index 0000000..f2fbc1c --- /dev/null +++ b/src/style/theme.scss @@ -0,0 +1,95 @@ +/* 浜櫧鑹� */ +html[data-theme="light"] { + --pure-theme-sub-menu-active-text: #000000d9; + --pure-theme-menu-bg: #fff; + --pure-theme-menu-hover: #f6f6f6; + --pure-theme-sub-menu-bg: #fff; + --pure-theme-menu-text: rgb(0 0 0 / 60%); + --pure-theme-sidebar-logo: #fff; + --pure-theme-menu-title-hover: #000; + --pure-theme-menu-active-before: #4091f7; +} + +/* 閬撳钃� */ +html[data-theme="default"] { + --pure-theme-sub-menu-active-text: #fff; + --pure-theme-menu-bg: #001529; + --pure-theme-menu-hover: rgb(64 145 247 / 15%); + --pure-theme-sub-menu-bg: #0f0303; + --pure-theme-menu-text: rgb(254 254 254 / 65%); + --pure-theme-sidebar-logo: #002140; + --pure-theme-menu-title-hover: #fff; + --pure-theme-menu-active-before: #4091f7; +} + +/* 娣辩传缃楀叞鑹� */ +html[data-theme="saucePurple"] { + --pure-theme-sub-menu-active-text: #fff; + --pure-theme-menu-bg: #130824; + --pure-theme-menu-hover: rgb(105 58 201 / 15%); + --pure-theme-sub-menu-bg: #000; + --pure-theme-menu-text: #7a80b4; + --pure-theme-sidebar-logo: #1f0c38; + --pure-theme-menu-title-hover: #fff; + --pure-theme-menu-active-before: #693ac9; +} + +/* 娣辩矇鑹� */ +html[data-theme="pink"] { + --pure-theme-sub-menu-active-text: #fff; + --pure-theme-menu-bg: #28081a; + --pure-theme-menu-hover: rgb(216 68 147 / 15%); + --pure-theme-sub-menu-bg: #000; + --pure-theme-menu-text: #7a80b4; + --pure-theme-sidebar-logo: #3f0d29; + --pure-theme-menu-title-hover: #fff; + --pure-theme-menu-active-before: #d84493; +} + +/* 鐚╃孩鑹� */ +html[data-theme="dusk"] { + --pure-theme-sub-menu-active-text: #fff; + --pure-theme-menu-bg: #2a0608; + --pure-theme-menu-hover: rgb(225 60 57 / 15%); + --pure-theme-sub-menu-bg: #000; + --pure-theme-menu-text: rgb(254 254 254 / 65.1%); + --pure-theme-sidebar-logo: #42090c; + --pure-theme-menu-title-hover: #fff; + --pure-theme-menu-active-before: #e13c39; +} + +/* 姗欑孩鑹� */ +html[data-theme="volcano"] { + --pure-theme-sub-menu-active-text: #fff; + --pure-theme-menu-bg: #2b0e05; + --pure-theme-menu-hover: rgb(232 95 51 / 15%); + --pure-theme-sub-menu-bg: #0f0603; + --pure-theme-menu-text: rgb(254 254 254 / 65%); + --pure-theme-sidebar-logo: #441708; + --pure-theme-menu-title-hover: #fff; + --pure-theme-menu-active-before: #e85f33; +} + +/* 缁垮疂鐭� */ +html[data-theme="mingQing"] { + --pure-theme-sub-menu-active-text: #fff; + --pure-theme-menu-bg: #032121; + --pure-theme-menu-hover: rgb(89 191 193 / 15%); + --pure-theme-sub-menu-bg: #000; + --pure-theme-menu-text: #7a80b4; + --pure-theme-sidebar-logo: #053434; + --pure-theme-menu-title-hover: #fff; + --pure-theme-menu-active-before: #59bfc1; +} + +/* 閰告缁� */ +html[data-theme="auroraGreen"] { + --pure-theme-sub-menu-active-text: #fff; + --pure-theme-menu-bg: #0b1e15; + --pure-theme-menu-hover: rgb(96 172 128 / 15%); + --pure-theme-sub-menu-bg: #000; + --pure-theme-menu-text: #7a80b4; + --pure-theme-sidebar-logo: #112f21; + --pure-theme-menu-title-hover: #fff; + --pure-theme-menu-active-before: #60ac80; +} diff --git a/src/style/transition.scss b/src/style/transition.scss new file mode 100644 index 0000000..c7274dd --- /dev/null +++ b/src/style/transition.scss @@ -0,0 +1,54 @@ +/* fade */ +.fade-enter-active, +.fade-leave-active { + transition: opacity 0.28s; +} + +.fade-enter, +.fade-leave-active { + opacity: 0; +} + +/* fade-transform */ +.fade-transform-leave-active, +.fade-transform-enter-active { + transition: all 0.5s; +} + +.fade-transform-enter-from { + opacity: 0; + transform: translateX(-30px); +} + +.fade-transform-leave-to { + opacity: 0; + transform: translateX(30px); +} + +/* breadcrumb transition */ +.breadcrumb-enter-active { + transition: all 0.4s; +} + +.breadcrumb-leave-active { + position: absolute; + transition: all 0.3s; +} + +.breadcrumb-enter-from, +.breadcrumb-leave-active { + opacity: 0; + transform: translateX(20px); +} + +/** + * @description 閲嶇疆el-menu鐨勫睍寮�鏀惰捣鍔ㄧ敾鏃堕暱 + */ +.outer-most .el-collapse-transition-leave-active, +.outer-most .el-collapse-transition-enter-active { + transition: 0.2s all ease-in-out !important; +} + +.horizontal-collapse-transition { + transition: var(--pure-transition-duration) all !important; +} diff --git a/src/utils/auth.ts b/src/utils/auth.ts new file mode 100644 index 0000000..f2b28cb --- /dev/null +++ b/src/utils/auth.ts @@ -0,0 +1,141 @@ +import Cookies from "js-cookie"; +import { useUserStoreHook } from "@/store/modules/user"; +import { storageLocal, isString, isIncludeAllChildren } from "@pureadmin/utils"; + +export interface DataInfo<T> { + /** token */ + accessToken: string; + /** `accessToken`鐨勮繃鏈熸椂闂达紙鏃堕棿鎴筹級 */ + expires: T; + /** 鐢ㄤ簬璋冪敤鍒锋柊accessToken鐨勬帴鍙f椂鎵�闇�鐨則oken */ + refreshToken: string; + /** 澶村儚 */ + avatar?: string; + /** 鐢ㄦ埛鍚� */ + username?: string; + /** 鏄电О */ + nickname?: string; + /** 褰撳墠鐧诲綍鐢ㄦ埛鐨勮鑹� */ + roles?: Array<string>; + /** 褰撳墠鐧诲綍鐢ㄦ埛鐨勬寜閽骇鍒潈闄� */ + permissions?: Array<string>; +} + +export const userKey = "user-info"; +export const TokenKey = "authorized-token"; +/** + * 閫氳繃`multiple-tabs`鏄惁鍦╜cookie`涓紝鍒ゆ柇鐢ㄦ埛鏄惁宸茬粡鐧诲綍绯荤粺锛� + * 浠庤�屾敮鎸佸鏍囩椤垫墦寮�宸茬粡鐧诲綍鐨勭郴缁熷悗鏃犻渶鍐嶇櫥褰曘�� + * 娴忚鍣ㄥ畬鍏ㄥ叧闂悗`multiple-tabs`灏嗚嚜鍔ㄤ粠`cookie`涓攢姣侊紝 + * 鍐嶆鎵撳紑娴忚鍣ㄩ渶瑕侀噸鏂扮櫥褰曠郴缁� + * */ +export const multipleTabsKey = "multiple-tabs"; + +/** 鑾峰彇`token` */ +export function getToken(): DataInfo<number> { + // 姝ゅ涓巂TokenKey`鐩稿悓锛屾鍐欐硶瑙e喅鍒濆鍖栨椂`Cookies`涓笉瀛樺湪`TokenKey`鎶ラ敊 + return Cookies.get(TokenKey) + ? JSON.parse(Cookies.get(TokenKey)) + : storageLocal().getItem(userKey); +} + +/** + * @description 璁剧疆`token`浠ュ強涓�浜涘繀瑕佷俊鎭苟閲囩敤鏃犳劅鍒锋柊`token`鏂规 + * 鏃犳劅鍒锋柊锛氬悗绔繑鍥瀈accessToken`锛堣闂帴鍙d娇鐢ㄧ殑`token`锛夈�乣refreshToken`锛堢敤浜庤皟鐢ㄥ埛鏂癭accessToken`鐨勬帴鍙f椂鎵�闇�鐨刞token`锛宍refreshToken`鐨勮繃鏈熸椂闂达紙姣斿30澶╋級搴斿ぇ浜巂accessToken`鐨勮繃鏈熸椂闂达紙姣斿2灏忔椂锛夛級銆乣expires`锛坄accessToken`鐨勮繃鏈熸椂闂达級 + * 灏哷accessToken`銆乣expires`銆乣refreshToken`杩欎笁鏉′俊鎭斁鍦╧ey鍊间负authorized-token鐨刢ookie閲岋紙杩囨湡鑷姩閿�姣侊級 + * 灏哷avatar`銆乣username`銆乣nickname`銆乣roles`銆乣permissions`銆乣refreshToken`銆乣expires`杩欎竷鏉′俊鎭斁鍦╧ey鍊间负`user-info`鐨刲ocalStorage閲岋紙鍒╃敤`multipleTabsKey`褰撴祻瑙堝櫒瀹屽叏鍏抽棴鍚庤嚜鍔ㄩ攢姣侊級 + */ +export function setToken(data: DataInfo<Date>) { + let expires = 0; + const { accessToken, refreshToken } = data; + const { isRemembered, loginDay } = useUserStoreHook(); + expires = new Date(data.expires).getTime(); // 濡傛灉鍚庣鐩存帴璁剧疆鏃堕棿鎴筹紝灏嗘澶勪唬鐮佹敼涓篹xpires = data.expires锛岀劧鍚庢妸涓婇潰鐨凞ataInfo<Date>鏀规垚DataInfo<number>鍗冲彲 + const cookieString = JSON.stringify({ accessToken, expires, refreshToken }); + + expires > 0 + ? Cookies.set(TokenKey, cookieString, { + expires: (expires - Date.now()) / 86400000 + }) + : Cookies.set(TokenKey, cookieString); + + Cookies.set( + multipleTabsKey, + "true", + isRemembered + ? { + expires: loginDay + } + : {} + ); + + function setUserKey({ avatar, username, nickname, roles, permissions }) { + useUserStoreHook().SET_AVATAR(avatar); + useUserStoreHook().SET_USERNAME(username); + useUserStoreHook().SET_NICKNAME(nickname); + useUserStoreHook().SET_ROLES(roles); + useUserStoreHook().SET_PERMS(permissions); + storageLocal().setItem(userKey, { + refreshToken, + expires, + avatar, + username, + nickname, + roles, + permissions + }); + } + + if (data.username && data.roles) { + const { username, roles } = data; + setUserKey({ + avatar: data?.avatar ?? "", + username, + nickname: data?.nickname ?? "", + roles, + permissions: data?.permissions ?? [] + }); + } else { + const avatar = + storageLocal().getItem<DataInfo<number>>(userKey)?.avatar ?? ""; + const username = + storageLocal().getItem<DataInfo<number>>(userKey)?.username ?? ""; + const nickname = + storageLocal().getItem<DataInfo<number>>(userKey)?.nickname ?? ""; + const roles = + storageLocal().getItem<DataInfo<number>>(userKey)?.roles ?? []; + const permissions = + storageLocal().getItem<DataInfo<number>>(userKey)?.permissions ?? []; + setUserKey({ + avatar, + username, + nickname, + roles, + permissions + }); + } +} + +/** 鍒犻櫎`token`浠ュ強key鍊间负`user-info`鐨刲ocalStorage淇℃伅 */ +export function removeToken() { + Cookies.remove(TokenKey); + Cookies.remove(multipleTabsKey); + storageLocal().removeItem(userKey); +} + +/** 鏍煎紡鍖杢oken锛坖wt鏍煎紡锛� */ +export const formatToken = (token: string): string => { + return "Bearer " + token; +}; + +/** 鏄惁鏈夋寜閽骇鍒殑鏉冮檺锛堟牴鎹櫥褰曟帴鍙h繑鍥炵殑`permissions`瀛楁杩涜鍒ゆ柇锛�*/ +export const hasPerms = (value: string | Array<string>): boolean => { + if (!value) return false; + const allPerms = "*:*:*"; + const { permissions } = useUserStoreHook(); + if (!permissions) return false; + if (permissions.length === 1 && permissions[0] === allPerms) return true; + const isAuths = isString(value) + ? permissions.includes(value) + : isIncludeAllChildren(value, permissions); + return isAuths ? true : false; +}; diff --git a/src/utils/globalPolyfills.ts b/src/utils/globalPolyfills.ts new file mode 100644 index 0000000..e9bc9a8 --- /dev/null +++ b/src/utils/globalPolyfills.ts @@ -0,0 +1,7 @@ +// 濡傛灉椤圭洰鍑虹幇 `global is not defined` 鎶ラ敊锛屽彲鑳芥槸鎮ㄥ紩鍏ユ煇涓簱鐨勯棶棰橈紝姣斿 aws-sdk-js https://github.com/aws/aws-sdk-js +// 瑙e喅鍔炴硶灏辨槸灏嗚鏂囦欢寮曞叆 src/main.ts 鍗冲彲 import "@/utils/globalPolyfills"; +if (typeof (window as any).global === "undefined") { + (window as any).global = window; +} + +export {}; diff --git a/src/utils/http/index.ts b/src/utils/http/index.ts new file mode 100644 index 0000000..19b5be2 --- /dev/null +++ b/src/utils/http/index.ts @@ -0,0 +1,194 @@ +import Axios, { + type AxiosInstance, + type AxiosRequestConfig, + type CustomParamsSerializer +} from "axios"; +import type { + PureHttpError, + RequestMethods, + PureHttpResponse, + PureHttpRequestConfig +} from "./types.d"; +import { stringify } from "qs"; +import NProgress from "../progress"; +import { getToken, formatToken } from "@/utils/auth"; +import { useUserStoreHook } from "@/store/modules/user"; + +// 鐩稿叧閰嶇疆璇峰弬鑰冿細www.axios-js.com/zh-cn/docs/#axios-request-config-1 +const defaultConfig: AxiosRequestConfig = { + // 璇锋眰瓒呮椂鏃堕棿 + timeout: 10000, + headers: { + Accept: "application/json, text/plain, */*", + "Content-Type": "application/json", + "X-Requested-With": "XMLHttpRequest" + }, + // 鏁扮粍鏍煎紡鍙傛暟搴忓垪鍖栵紙https://github.com/axios/axios/issues/5142锛� + paramsSerializer: { + serialize: stringify as unknown as CustomParamsSerializer + } +}; + +class PureHttp { + constructor() { + this.httpInterceptorsRequest(); + this.httpInterceptorsResponse(); + } + + /** `token`杩囨湡鍚庯紝鏆傚瓨寰呮墽琛岀殑璇锋眰 */ + private static requests = []; + + /** 闃叉閲嶅鍒锋柊`token` */ + private static isRefreshing = false; + + /** 鍒濆鍖栭厤缃璞� */ + private static initConfig: PureHttpRequestConfig = {}; + + /** 淇濆瓨褰撳墠`Axios`瀹炰緥瀵硅薄 */ + private static axiosInstance: AxiosInstance = Axios.create(defaultConfig); + + /** 閲嶈繛鍘熷璇锋眰 */ + private static retryOriginalRequest(config: PureHttpRequestConfig) { + return new Promise(resolve => { + PureHttp.requests.push((token: string) => { + config.headers["Authorization"] = formatToken(token); + resolve(config); + }); + }); + } + + /** 璇锋眰鎷︽埅 */ + private httpInterceptorsRequest(): void { + PureHttp.axiosInstance.interceptors.request.use( + async (config: PureHttpRequestConfig): Promise<any> => { + // 寮�鍚繘搴︽潯鍔ㄧ敾 + NProgress.start(); + // 浼樺厛鍒ゆ柇post/get绛夋柟娉曟槸鍚︿紶鍏ュ洖璋冿紝鍚﹀垯鎵ц鍒濆鍖栬缃瓑鍥炶皟 + if (typeof config.beforeRequestCallback === "function") { + config.beforeRequestCallback(config); + return config; + } + if (PureHttp.initConfig.beforeRequestCallback) { + PureHttp.initConfig.beforeRequestCallback(config); + return config; + } + /** 璇锋眰鐧藉悕鍗曪紝鏀剧疆涓�浜涗笉闇�瑕乣token`鐨勬帴鍙o紙閫氳繃璁剧疆璇锋眰鐧藉悕鍗曪紝闃叉`token`杩囨湡鍚庡啀璇锋眰閫犳垚鐨勬寰幆闂锛� */ + const whiteList = ["/refresh-token", "/login"]; + return whiteList.some(url => config.url.endsWith(url)) + ? config + : new Promise(resolve => { + const data = getToken(); + if (data) { + const now = new Date().getTime(); + const expired = parseInt(data.expires) - now <= 0; + if (expired) { + if (!PureHttp.isRefreshing) { + PureHttp.isRefreshing = true; + // token杩囨湡鍒锋柊 + useUserStoreHook() + .handRefreshToken({ refreshToken: data.refreshToken }) + .then(res => { + const token = res.data.accessToken; + config.headers["Authorization"] = formatToken(token); + PureHttp.requests.forEach(cb => cb(token)); + PureHttp.requests = []; + }) + .finally(() => { + PureHttp.isRefreshing = false; + }); + } + resolve(PureHttp.retryOriginalRequest(config)); + } else { + config.headers["Authorization"] = formatToken( + data.accessToken + ); + resolve(config); + } + } else { + resolve(config); + } + }); + }, + error => { + return Promise.reject(error); + } + ); + } + + /** 鍝嶅簲鎷︽埅 */ + private httpInterceptorsResponse(): void { + const instance = PureHttp.axiosInstance; + instance.interceptors.response.use( + (response: PureHttpResponse) => { + const $config = response.config; + // 鍏抽棴杩涘害鏉″姩鐢� + NProgress.done(); + // 浼樺厛鍒ゆ柇post/get绛夋柟娉曟槸鍚︿紶鍏ュ洖璋冿紝鍚﹀垯鎵ц鍒濆鍖栬缃瓑鍥炶皟 + if (typeof $config.beforeResponseCallback === "function") { + $config.beforeResponseCallback(response); + return response.data; + } + if (PureHttp.initConfig.beforeResponseCallback) { + PureHttp.initConfig.beforeResponseCallback(response); + return response.data; + } + return response.data; + }, + (error: PureHttpError) => { + const $error = error; + $error.isCancelRequest = Axios.isCancel($error); + // 鍏抽棴杩涘害鏉″姩鐢� + NProgress.done(); + // 鎵�鏈夌殑鍝嶅簲寮傚父 鍖哄垎鏉ユ簮涓哄彇娑堣姹�/闈炲彇娑堣姹� + return Promise.reject($error); + } + ); + } + + /** 閫氱敤璇锋眰宸ュ叿鍑芥暟 */ + public request<T>( + method: RequestMethods, + url: string, + param?: AxiosRequestConfig, + axiosConfig?: PureHttpRequestConfig + ): Promise<T> { + const config = { + method, + url, + ...param, + ...axiosConfig + } as PureHttpRequestConfig; + + // 鍗曠嫭澶勭悊鑷畾涔夎姹�/鍝嶅簲鍥炶皟 + return new Promise((resolve, reject) => { + PureHttp.axiosInstance + .request(config) + .then((response: undefined) => { + resolve(response); + }) + .catch(error => { + reject(error); + }); + }); + } + + /** 鍗曠嫭鎶界鐨刞post`宸ュ叿鍑芥暟 */ + public post<T, P>( + url: string, + params?: AxiosRequestConfig<P>, + config?: PureHttpRequestConfig + ): Promise<T> { + return this.request<T>("post", url, params, config); + } + + /** 鍗曠嫭鎶界鐨刞get`宸ュ叿鍑芥暟 */ + public get<T, P>( + url: string, + params?: AxiosRequestConfig<P>, + config?: PureHttpRequestConfig + ): Promise<T> { + return this.request<T>("get", url, params, config); + } +} + +export const http = new PureHttp(); diff --git a/src/utils/http/types.d.ts b/src/utils/http/types.d.ts new file mode 100644 index 0000000..ef7c25f --- /dev/null +++ b/src/utils/http/types.d.ts @@ -0,0 +1,47 @@ +import type { + Method, + AxiosError, + AxiosResponse, + AxiosRequestConfig +} from "axios"; + +export type resultType = { + accessToken?: string; +}; + +export type RequestMethods = Extract< + Method, + "get" | "post" | "put" | "delete" | "patch" | "option" | "head" +>; + +export interface PureHttpError extends AxiosError { + isCancelRequest?: boolean; +} + +export interface PureHttpResponse extends AxiosResponse { + config: PureHttpRequestConfig; +} + +export interface PureHttpRequestConfig extends AxiosRequestConfig { + beforeRequestCallback?: (request: PureHttpRequestConfig) => void; + beforeResponseCallback?: (response: PureHttpResponse) => void; +} + +export default class PureHttp { + request<T>( + method: RequestMethods, + url: string, + param?: AxiosRequestConfig, + axiosConfig?: PureHttpRequestConfig + ): Promise<T>; + post<T, P>( + url: string, + params?: P, + config?: PureHttpRequestConfig + ): Promise<T>; + get<T, P>( + url: string, + params?: P, + config?: PureHttpRequestConfig + ): Promise<T>; +} diff --git a/src/utils/localforage/index.ts b/src/utils/localforage/index.ts new file mode 100644 index 0000000..013545f --- /dev/null +++ b/src/utils/localforage/index.ts @@ -0,0 +1,109 @@ +import forage from "localforage"; +import type { LocalForage, ProxyStorage, ExpiresData } from "./types.d"; + +class StorageProxy implements ProxyStorage { + protected storage: LocalForage; + constructor(storageModel) { + this.storage = storageModel; + this.storage.config({ + // 棣栭�塈ndexedDB浣滀负绗竴椹卞姩锛屼笉鏀寔IndexedDB浼氳嚜鍔ㄩ檷绾у埌localStorage锛圵ebSQL琚純鐢紝璇︽儏鐪媓ttps://developer.chrome.com/blog/deprecating-web-sql锛� + driver: [this.storage.INDEXEDDB, this.storage.LOCALSTORAGE], + name: "pure-admin" + }); + } + + /** + * @description 灏嗗搴旈敭鍚嶇殑鏁版嵁淇濆瓨鍒扮绾夸粨搴� + * @param k 閿悕 + * @param v 閿�� + * @param m 缂撳瓨鏃堕棿锛堝崟浣峘鍒哷锛岄粯璁0`鍒嗛挓锛屾案涔呯紦瀛橈級 + */ + public async setItem<T>(k: string, v: T, m = 0): Promise<T> { + return new Promise((resolve, reject) => { + this.storage + .setItem(k, { + data: v, + expires: m ? new Date().getTime() + m * 60 * 1000 : 0 + }) + .then(value => { + resolve(value.data); + }) + .catch(err => { + reject(err); + }); + }); + } + + /** + * @description 浠庣绾夸粨搴撲腑鑾峰彇瀵瑰簲閿悕鐨勫�� + * @param k 閿悕 + */ + public async getItem<T>(k: string): Promise<T> { + return new Promise((resolve, reject) => { + this.storage + .getItem(k) + .then((value: ExpiresData<T>) => { + value && (value.expires > new Date().getTime() || value.expires === 0) + ? resolve(value.data) + : resolve(null); + }) + .catch(err => { + reject(err); + }); + }); + } + + /** + * @description 浠庣绾夸粨搴撲腑鍒犻櫎瀵瑰簲閿悕鐨勫�� + * @param k 閿悕 + */ + public async removeItem(k: string) { + return new Promise<void>((resolve, reject) => { + this.storage + .removeItem(k) + .then(() => { + resolve(); + }) + .catch(err => { + reject(err); + }); + }); + } + + /** + * @description 浠庣绾夸粨搴撲腑鍒犻櫎鎵�鏈夌殑閿悕锛岄噸缃暟鎹簱 + */ + public async clear() { + return new Promise<void>((resolve, reject) => { + this.storage + .clear() + .then(() => { + resolve(); + }) + .catch(err => { + reject(err); + }); + }); + } + + /** + * @description 鑾峰彇鏁版嵁浠撳簱涓墍鏈夌殑key + */ + public async keys() { + return new Promise<string[]>((resolve, reject) => { + this.storage + .keys() + .then(keys => { + resolve(keys); + }) + .catch(err => { + reject(err); + }); + }); + } +} + +/** + * 浜屾灏佽 [localforage](https://localforage.docschina.org/) 鏀寔璁剧疆杩囨湡鏃堕棿锛屾彁渚涘畬鏁寸殑绫诲瀷鎻愮ず + */ +export const localForage = () => new StorageProxy(forage); diff --git a/src/utils/localforage/types.d.ts b/src/utils/localforage/types.d.ts new file mode 100644 index 0000000..b013c5b --- /dev/null +++ b/src/utils/localforage/types.d.ts @@ -0,0 +1,166 @@ +// https://github.com/localForage/localForage/blob/master/typings/localforage.d.ts + +interface LocalForageDbInstanceOptions { + name?: string; + + storeName?: string; +} + +interface LocalForageOptions extends LocalForageDbInstanceOptions { + driver?: string | string[]; + + size?: number; + + version?: number; + + description?: string; +} + +interface LocalForageDbMethodsCore { + getItem<T>( + key: string, + callback?: (err: any, value: T | null) => void + ): Promise<T | null>; + + setItem<T>( + key: string, + value: T, + callback?: (err: any, value: T) => void + ): Promise<T>; + + removeItem(key: string, callback?: (err: any) => void): Promise<void>; + + clear(callback?: (err: any) => void): Promise<void>; + + length(callback?: (err: any, numberOfKeys: number) => void): Promise<number>; + + key( + keyIndex: number, + callback?: (err: any, key: string) => void + ): Promise<string>; + + keys(callback?: (err: any, keys: string[]) => void): Promise<string[]>; + + iterate<T, U>( + iteratee: (value: T, key: string, iterationNumber: number) => U, + callback?: (err: any, result: U) => void + ): Promise<U>; +} + +interface LocalForageDropInstanceFn { + ( + dbInstanceOptions?: LocalForageDbInstanceOptions, + callback?: (err: any) => void + ): Promise<void>; +} + +interface LocalForageDriverMethodsOptional { + dropInstance?: LocalForageDropInstanceFn; +} + +// duplicating LocalForageDriverMethodsOptional to preserve TS v2.0 support, +// since Partial<> isn't supported there +interface LocalForageDbMethodsOptional { + dropInstance: LocalForageDropInstanceFn; +} + +interface LocalForageDriverDbMethods + extends LocalForageDbMethodsCore, + LocalForageDriverMethodsOptional {} + +interface LocalForageDriverSupportFunc { + (): Promise<boolean>; +} + +interface LocalForageDriver extends LocalForageDriverDbMethods { + _driver: string; + + _initStorage(options: LocalForageOptions): void; + + _support?: boolean | LocalForageDriverSupportFunc; +} + +interface LocalForageSerializer { + serialize<T>( + value: T | ArrayBuffer | Blob, + callback: (value: string, error: any) => void + ): void; + + deserialize<T>(value: string): T | ArrayBuffer | Blob; + + stringToBuffer(serializedString: string): ArrayBuffer; + + bufferToString(buffer: ArrayBuffer): string; +} + +interface LocalForageDbMethods + extends LocalForageDbMethodsCore, + LocalForageDbMethodsOptional {} + +export interface LocalForage extends LocalForageDbMethods { + LOCALSTORAGE: string; + WEBSQL: string; + INDEXEDDB: string; + + /** + * Set and persist localForage options. This must be called before any other calls to localForage are made, but can be called after localForage is loaded. + * If you set any config values with this method they will persist after driver changes, so you can call config() then setDriver() + * @param {LocalForageOptions} options? + */ + config(options: LocalForageOptions): boolean; + config(options: string): any; + config(): LocalForageOptions; + + /** + * Create a new instance of localForage to point to a different store. + * All the configuration options used by config are supported. + * @param {LocalForageOptions} options + */ + createInstance(options: LocalForageOptions): LocalForage; + + driver(): string; + + /** + * Force usage of a particular driver or drivers, if available. + * @param {string} driver + */ + setDriver( + driver: string | string[], + callback?: () => void, + errorCallback?: (error: any) => void + ): Promise<void>; + + defineDriver( + driver: LocalForageDriver, + callback?: () => void, + errorCallback?: (error: any) => void + ): Promise<void>; + + /** + * Return a particular driver + * @param {string} driver + */ + getDriver(driver: string): Promise<LocalForageDriver>; + + getSerializer( + callback?: (serializer: LocalForageSerializer) => void + ): Promise<LocalForageSerializer>; + + supports(driverName: string): boolean; + + ready(callback?: (error: any) => void): Promise<void>; +} + +// Customize + +export interface ProxyStorage { + setItem<T>(k: string, v: T, m: number): Promise<T>; + getItem<T>(k: string): Promise<T>; + removeItem(k: string): Promise<void>; + clear(): Promise<void>; +} + +export interface ExpiresData<T> { + data: T; + expires: number; +} diff --git a/src/utils/message.ts b/src/utils/message.ts new file mode 100644 index 0000000..c45c5d7 --- /dev/null +++ b/src/utils/message.ts @@ -0,0 +1,89 @@ +import type { VNode } from "vue"; +import { isFunction } from "@pureadmin/utils"; +import { type MessageHandler, ElMessage } from "element-plus"; + +type messageStyle = "el" | "antd"; +type messageTypes = "info" | "success" | "warning" | "error"; + +interface MessageParams { + /** 娑堟伅绫诲瀷锛屽彲閫� `info` 銆乣success` 銆乣warning` 銆乣error` 锛岄粯璁� `info` */ + type?: messageTypes; + /** 鏄惁绾壊锛岄粯璁� `false` */ + plain?: boolean; + /** 鑷畾涔夊浘鏍囷紝璇ュ睘鎬т細瑕嗙洊 `type` 鐨勫浘鏍� */ + icon?: any; + /** 鏄惁灏� `message` 灞炴�т綔涓� `HTML` 鐗囨澶勭悊锛岄粯璁� `false` */ + dangerouslyUseHTMLString?: boolean; + /** 娑堟伅椋庢牸锛屽彲閫� `el` 銆乣antd` 锛岄粯璁� `antd` */ + customClass?: messageStyle; + /** 鏄剧ず鏃堕棿锛屽崟浣嶄负姣銆傝涓� `0` 鍒欎笉浼氳嚜鍔ㄥ叧闂紝`element-plus` 榛樿鏄� `3000` 锛屽钩鍙版敼鎴愰粯璁� `2000` */ + duration?: number; + /** 鏄惁鏄剧ず鍏抽棴鎸夐挳锛岄粯璁ゅ�� `false` */ + showClose?: boolean; + /** `Message` 璺濈绐楀彛椤堕儴鐨勫亸绉婚噺锛岄粯璁� `16` */ + offset?: number; + /** 璁剧疆缁勪欢鐨勬牴鍏冪礌锛岄粯璁� `document.body` */ + appendTo?: string | HTMLElement; + /** 鍚堝苟鍐呭鐩稿悓鐨勬秷鎭紝涓嶆敮鎸� `VNode` 绫诲瀷鐨勬秷鎭紝榛樿鍊� `false` */ + grouping?: boolean; + /** 閲嶅娆℃暟锛岀被浼间簬 `Badge` 銆傚綋鍜� `grouping` 灞炴�т竴璧蜂娇鐢ㄦ椂浣滀负鍒濆鏁伴噺浣跨敤锛岄粯璁ゅ�� `1` */ + repeatNum?: number; + /** 鍏抽棴鏃剁殑鍥炶皟鍑芥暟, 鍙傛暟涓鸿鍏抽棴鐨� `message` 瀹炰緥 */ + onClose?: Function | null; +} + +/** 鐢ㄦ硶闈炲父绠�鍗曪紝鍙傝�� src/views/components/message/index.vue 鏂囦欢 */ + +/** + * `Message` 娑堟伅鎻愮ず鍑芥暟 + */ +const message = ( + message: string | VNode | (() => VNode), + params?: MessageParams +): MessageHandler => { + if (!params) { + return ElMessage({ + message, + customClass: "pure-message" + }); + } else { + const { + icon, + type = "info", + plain = false, + dangerouslyUseHTMLString = false, + customClass = "antd", + duration = 2000, + showClose = false, + offset = 16, + appendTo = document.body, + grouping = false, + repeatNum = 1, + onClose + } = params; + + return ElMessage({ + message, + icon, + type, + plain, + dangerouslyUseHTMLString, + duration, + showClose, + offset, + appendTo, + grouping, + repeatNum, + // 鍏ㄥ眬鎼� pure-message 鍗冲彲鐭ラ亾璇ョ被鐨勬牱寮忎綅缃� + customClass: customClass === "antd" ? "pure-message" : "", + onClose: () => (isFunction(onClose) ? onClose() : null) + }); + } +}; + +/** + * 鍏抽棴鎵�鏈� `Message` 娑堟伅鎻愮ず鍑芥暟 + */ +const closeAllMessage = (): void => ElMessage.closeAll(); + +export { message, closeAllMessage }; diff --git a/src/utils/mitt.ts b/src/utils/mitt.ts new file mode 100644 index 0000000..411f876 --- /dev/null +++ b/src/utils/mitt.ts @@ -0,0 +1,14 @@ +import type { Emitter } from "mitt"; +import mitt from "mitt"; + +/** 鍏ㄥ眬鍏叡浜嬩欢闇�瑕佸湪姝ゅ娣诲姞绫诲瀷 */ +type Events = { + openPanel: string; + tagOnClick: string; + logoChange: boolean; + tagViewsChange: string; + changLayoutRoute: string; + tagViewsShowModel: string; +}; + +export const emitter: Emitter<Events> = mitt<Events>(); diff --git a/src/utils/preventDefault.ts b/src/utils/preventDefault.ts new file mode 100644 index 0000000..42da8df --- /dev/null +++ b/src/utils/preventDefault.ts @@ -0,0 +1,28 @@ +import { useEventListener } from "@vueuse/core"; + +/** 鏄惁涓篳img`鏍囩 */ +function isImgElement(element) { + return typeof HTMLImageElement !== "undefined" + ? element instanceof HTMLImageElement + : element.tagName.toLowerCase() === "img"; +} + +// 鍦� src/main.ts 寮曞叆骞惰皟鐢ㄥ嵆鍙� import { addPreventDefault } from "@/utils/preventDefault"; addPreventDefault(); +export const addPreventDefault = () => { + // 闃绘閫氳繃閿洏F12蹇嵎閿墦寮�娴忚鍣ㄥ紑鍙戣�呭伐鍏烽潰鏉� + useEventListener( + window.document, + "keydown", + ev => ev.key === "F12" && ev.preventDefault() + ); + // 闃绘娴忚鍣ㄩ粯璁ょ殑鍙抽敭鑿滃崟寮瑰嚭锛堜笉浼氬奖鍝嶈嚜瀹氫箟鍙抽敭浜嬩欢锛� + useEventListener(window.document, "contextmenu", ev => ev.preventDefault()); + // 闃绘椤甸潰鍏冪礌閫変腑 + useEventListener(window.document, "selectstart", ev => ev.preventDefault()); + // 娴忚鍣ㄤ腑鍥剧墖閫氬父榛樿鏄彲鎷栧姩鐨勶紝骞朵笖鍙互鍦ㄦ柊鏍囩椤垫垨绐楀彛涓墦寮�锛屾垨鑰呭皢鍏舵嫋鍔ㄥ埌鍏朵粬搴旂敤绋嬪簭涓紝姝ゅ灏嗗叾绂佺敤锛屼娇鍏堕粯璁や笉鍙嫋鍔� + useEventListener( + window.document, + "dragstart", + ev => isImgElement(ev?.target) && ev.preventDefault() + ); +}; diff --git a/src/utils/print.ts b/src/utils/print.ts new file mode 100644 index 0000000..ce005d5 --- /dev/null +++ b/src/utils/print.ts @@ -0,0 +1,223 @@ +interface PrintFunction { + extendOptions: Function; + getStyle: Function; + setDomHeight: Function; + toPrint: Function; +} + +const Print = function (dom, options?: object): PrintFunction { + options = options || {}; + // @ts-expect-error + if (!(this instanceof Print)) return new Print(dom, options); + // @ts-expect-error + this.conf = { + styleStr: "", + // Elements that need to dynamically get and set the height + setDomHeightArr: [], + // Callback before printing + printBeforeFn: null, + // Callback after printing + printDoneCallBack: null + }; + // @ts-expect-error + for (const key in this.conf) { + if (key && options.hasOwnProperty(key)) { + // @ts-expect-error + this.conf[key] = options[key]; + } + } + if (typeof dom === "string") { + // @ts-expect-error + this.dom = document.querySelector(dom); + } else { + // @ts-expect-error + this.dom = this.isDOM(dom) ? dom : dom.$el; + } + // @ts-expect-error + if (this.conf.setDomHeightArr && this.conf.setDomHeightArr.length) { + // @ts-expect-error + this.setDomHeight(this.conf.setDomHeightArr); + } + // @ts-expect-error + this.init(); +}; + +Print.prototype = { + /** + * init + */ + init: function (): void { + const content = this.getStyle() + this.getHtml(); + this.writeIframe(content); + }, + /** + * Configuration property extension + * @param {Object} obj + * @param {Object} obj2 + */ + extendOptions: function <T>(obj, obj2: T): T { + for (const k in obj2) { + obj[k] = obj2[k]; + } + return obj; + }, + /** + Copy all styles of the original page + */ + getStyle: function (): string { + let str = ""; + const styles: NodeListOf<Element> = document.querySelectorAll("style,link"); + for (let i = 0; i < styles.length; i++) { + str += styles[i].outerHTML; + } + str += `<style>.no-print{display:none;}${this.conf.styleStr}</style>`; + return str; + }, + // form assignment + getHtml: function (): Element { + const inputs = document.querySelectorAll("input"); + const selects = document.querySelectorAll("select"); + const textareas = document.querySelectorAll("textarea"); + const canvass = document.querySelectorAll("canvas"); + + for (let k = 0; k < inputs.length; k++) { + if (inputs[k].type == "checkbox" || inputs[k].type == "radio") { + if (inputs[k].checked == true) { + inputs[k].setAttribute("checked", "checked"); + } else { + inputs[k].removeAttribute("checked"); + } + } else if (inputs[k].type == "text") { + inputs[k].setAttribute("value", inputs[k].value); + } else { + inputs[k].setAttribute("value", inputs[k].value); + } + } + + for (let k2 = 0; k2 < textareas.length; k2++) { + if (textareas[k2].type == "textarea") { + textareas[k2].innerHTML = textareas[k2].value; + } + } + + for (let k3 = 0; k3 < selects.length; k3++) { + if (selects[k3].type == "select-one") { + const child = selects[k3].children; + for (const i in child) { + if (child[i].tagName == "OPTION") { + if ((child[i] as any).selected == true) { + child[i].setAttribute("selected", "selected"); + } else { + child[i].removeAttribute("selected"); + } + } + } + } + } + + for (let k4 = 0; k4 < canvass.length; k4++) { + const imageURL = canvass[k4].toDataURL("image/png"); + const img = document.createElement("img"); + img.src = imageURL; + img.setAttribute("style", "max-width: 100%;"); + img.className = "isNeedRemove"; + canvass[k4].parentNode.insertBefore(img, canvass[k4].nextElementSibling); + } + + return this.dom.outerHTML; + }, + /** + create iframe + */ + writeIframe: function (content) { + let w: Document | Window; + let doc: Document; + const iframe: HTMLIFrameElement = document.createElement("iframe"); + const f: HTMLIFrameElement = document.body.appendChild(iframe); + iframe.id = "myIframe"; + iframe.setAttribute( + "style", + "position:absolute;width:0;height:0;top:-10px;left:-10px;" + ); + + // eslint-disable-next-line prefer-const + w = f.contentWindow || f.contentDocument; + + // eslint-disable-next-line prefer-const + doc = f.contentDocument || f.contentWindow.document; + doc.open(); + doc.write(content); + doc.close(); + + const removes = document.querySelectorAll(".isNeedRemove"); + for (let k = 0; k < removes.length; k++) { + removes[k].parentNode.removeChild(removes[k]); + } + + // eslint-disable-next-line @typescript-eslint/no-this-alias + const _this = this; + iframe.onload = function (): void { + // Before popping, callback + if (_this.conf.printBeforeFn) { + _this.conf.printBeforeFn({ doc }); + } + _this.toPrint(w); + setTimeout(function () { + document.body.removeChild(iframe); + // After popup, callback + if (_this.conf.printDoneCallBack) { + _this.conf.printDoneCallBack(); + } + }, 100); + }; + }, + /** + Print + */ + toPrint: function (frameWindow): void { + try { + setTimeout(function () { + frameWindow.focus(); + try { + if (!frameWindow.document.execCommand("print", false, null)) { + frameWindow.print(); + } + } catch { + frameWindow.print(); + } + frameWindow.close(); + }, 10); + } catch (err) { + console.error(err); + } + }, + isDOM: + typeof HTMLElement === "object" + ? function (obj) { + return obj instanceof HTMLElement; + } + : function (obj) { + return ( + obj && + typeof obj === "object" && + obj.nodeType === 1 && + typeof obj.nodeName === "string" + ); + }, + /** + * Set the height of the specified dom element by getting the existing height of the dom element and setting + * @param {Array} arr + */ + setDomHeight(arr) { + if (arr && arr.length) { + arr.forEach(name => { + const domArr = document.querySelectorAll(name); + domArr.forEach(dom => { + dom.style.height = dom.offsetHeight + "px"; + }); + }); + } + } +}; + +export default Print; diff --git a/src/utils/progress/index.ts b/src/utils/progress/index.ts new file mode 100644 index 0000000..d309862 --- /dev/null +++ b/src/utils/progress/index.ts @@ -0,0 +1,17 @@ +import NProgress from "nprogress"; +import "nprogress/nprogress.css"; + +NProgress.configure({ + // 鍔ㄧ敾鏂瑰紡 + easing: "ease", + // 閫掑杩涘害鏉$殑閫熷害 + speed: 500, + // 鏄惁鏄剧ず鍔犺浇ico + showSpinner: false, + // 鑷姩閫掑闂撮殧 + trickleSpeed: 200, + // 鍒濆鍖栨椂鐨勬渶灏忕櫨鍒嗘瘮 + minimum: 0.3 +}); + +export default NProgress; diff --git a/src/utils/propTypes.ts b/src/utils/propTypes.ts new file mode 100644 index 0000000..a4d67ec --- /dev/null +++ b/src/utils/propTypes.ts @@ -0,0 +1,39 @@ +import type { CSSProperties, VNodeChild } from "vue"; +import { + createTypes, + toValidableType, + type VueTypesInterface, + type VueTypeValidableDef +} from "vue-types"; + +export type VueNode = VNodeChild | JSX.Element; + +type PropTypes = VueTypesInterface & { + readonly style: VueTypeValidableDef<CSSProperties>; + readonly VNodeChild: VueTypeValidableDef<VueNode>; +}; + +const newPropTypes = createTypes({ + func: undefined, + bool: undefined, + string: undefined, + number: undefined, + object: undefined, + integer: undefined +}) as PropTypes; + +// 浠� vue-types v5.0 寮�濮嬶紝extend()鏂规硶宸茬粡搴熷純锛屽綋鍓嶅凡鏀逛负瀹樻柟鎺ㄨ崘鐨凟S6+鏂规硶 https://dwightjack.github.io/vue-types/advanced/extending-vue-types.html#the-extend-method +export default class propTypes extends newPropTypes { + // a native-like validator that supports the `.validable` method + static get style() { + return toValidableType("style", { + type: [String, Object] + }); + } + + static get VNodeChild() { + return toValidableType("VNodeChild", { + type: undefined + }); + } +} diff --git a/src/utils/responsive.ts b/src/utils/responsive.ts new file mode 100644 index 0000000..356efb4 --- /dev/null +++ b/src/utils/responsive.ts @@ -0,0 +1,42 @@ +// 鍝嶅簲寮弒torage +import type { App } from "vue"; +import Storage from "responsive-storage"; +import { routerArrays } from "@/layout/types"; +import { responsiveStorageNameSpace } from "@/config"; + +export const injectResponsiveStorage = (app: App, config: PlatformConfigs) => { + const nameSpace = responsiveStorageNameSpace(); + const configObj = Object.assign( + { + // layout妯″紡浠ュ強涓婚 + layout: Storage.getData("layout", nameSpace) ?? { + layout: config.Layout ?? "vertical", + theme: config.Theme ?? "light", + darkMode: config.DarkMode ?? false, + sidebarStatus: config.SidebarStatus ?? true, + epThemeColor: config.EpThemeColor ?? "#409EFF", + themeColor: config.Theme ?? "light", // 涓婚鑹诧紙瀵瑰簲绯荤粺閰嶇疆涓殑涓婚鑹诧紝涓巘heme涓嶅悓鐨勬槸瀹冧笉浼氬彈鍒版祬鑹层�佹繁鑹叉暣浣撻鏍煎垏鎹㈢殑褰卞搷锛屽彧浼氬湪鎵嬪姩鐐瑰嚮涓婚鑹叉椂鏀瑰彉锛� + overallStyle: config.OverallStyle ?? "light" // 鏁翠綋椋庢牸锛堟祬鑹诧細light銆佹繁鑹诧細dark銆佽嚜鍔細system锛� + }, + // 绯荤粺閰嶇疆-鐣岄潰鏄剧ず + configure: Storage.getData("configure", nameSpace) ?? { + grey: config.Grey ?? false, + weak: config.Weak ?? false, + hideTabs: config.HideTabs ?? false, + hideFooter: config.HideFooter ?? true, + showLogo: config.ShowLogo ?? true, + showModel: config.ShowModel ?? "smart", + multiTagsCache: config.MultiTagsCache ?? false, + stretch: config.Stretch ?? false + } + }, + config.MultiTagsCache + ? { + // 榛樿鏄剧ず椤剁骇鑿滃崟tag + tags: Storage.getData("tags", nameSpace) ?? routerArrays + } + : {} + ); + + app.use(Storage, { nameSpace, memory: configObj }); +}; diff --git a/src/utils/sso.ts b/src/utils/sso.ts new file mode 100644 index 0000000..18021d0 --- /dev/null +++ b/src/utils/sso.ts @@ -0,0 +1,59 @@ +import { removeToken, setToken, type DataInfo } from "./auth"; +import { subBefore, getQueryMap } from "@pureadmin/utils"; + +/** + * 绠�鐗堝墠绔崟鐐圭櫥褰曪紝鏍规嵁瀹為檯涓氬姟鑷缂栧啓锛屽钩鍙板惎鍔ㄥ悗鏈湴鍙互璺冲悗闈㈣繖涓摼鎺ヨ繘琛屾祴璇� http://localhost:8848/#/permission/page/index?username=sso&roles=admin&accessToken=eyJhbGciOiJIUzUxMiJ9.admin + * 鍒掗噸鐐癸細 + * 鍒ゆ柇鏄惁涓哄崟鐐圭櫥褰曪紝涓嶄负鍒欑洿鎺ヨ繑鍥炰笉鍐嶈繘琛屼换浣曢�昏緫澶勭悊锛屼笅闈㈡槸鍗曠偣鐧诲綍鍚庣殑閫昏緫澶勭悊 + * 1.娓呯┖鏈湴鏃т俊鎭紱 + * 2.鑾峰彇url涓殑閲嶈鍙傛暟淇℃伅锛岀劧鍚庨�氳繃 setToken 淇濆瓨鍦ㄦ湰鍦帮紱 + * 3.鍒犻櫎涓嶉渶瑕佹樉绀哄湪 url 鐨勫弬鏁� + * 4.浣跨敤 window.location.replace 璺宠浆姝g‘椤甸潰 + */ +(function () { + // 鑾峰彇 url 涓殑鍙傛暟 + const params = getQueryMap(location.href) as DataInfo<Date>; + const must = ["username", "roles", "accessToken"]; + const mustLength = must.length; + if (Object.keys(params).length !== mustLength) return; + + // url 鍙傛暟婊¤冻 must 閲岀殑鍏ㄩ儴鍊硷紝鎵嶅垽瀹氫负鍗曠偣鐧诲綍锛岄伩鍏嶉潪鍗曠偣鐧诲綍鏃跺埛鏂伴〉闈㈡棤闄愬惊鐜� + let sso = []; + let start = 0; + + while (start < mustLength) { + if (Object.keys(params).includes(must[start]) && sso.length <= mustLength) { + sso.push(must[start]); + } else { + sso = []; + } + start++; + } + + if (sso.length === mustLength) { + // 鍒ゅ畾涓哄崟鐐圭櫥褰� + + // 娓呯┖鏈湴鏃т俊鎭� + removeToken(); + + // 淇濆瓨鏂颁俊鎭埌鏈湴 + setToken(params); + + // 鍒犻櫎涓嶉渶瑕佹樉绀哄湪 url 鐨勫弬鏁� + delete params.roles; + delete params.accessToken; + + const newUrl = `${location.origin}${location.pathname}${subBefore( + location.hash, + "?" + )}?${JSON.stringify(params) + .replace(/["{}]/g, "") + .replace(/:/g, "=") + .replace(/,/g, "&")}`; + + // 鏇挎崲鍘嗗彶璁板綍椤� + window.location.replace(newUrl); + } else { + return; + } +})(); diff --git a/src/utils/tree.ts b/src/utils/tree.ts new file mode 100644 index 0000000..f8f3783 --- /dev/null +++ b/src/utils/tree.ts @@ -0,0 +1,188 @@ +/** + * @description 鎻愬彇鑿滃崟鏍戜腑鐨勬瘡涓�椤箄niqueId + * @param tree 鏍� + * @returns 姣忎竴椤箄niqueId缁勬垚鐨勬暟缁� + */ +export const extractPathList = (tree: any[]): any => { + if (!Array.isArray(tree)) { + console.warn("tree must be an array"); + return []; + } + if (!tree || tree.length === 0) return []; + const expandedPaths: Array<number | string> = []; + for (const node of tree) { + const hasChildren = node.children && node.children.length > 0; + if (hasChildren) { + extractPathList(node.children); + } + expandedPaths.push(node.uniqueId); + } + return expandedPaths; +}; + +/** + * @description 濡傛灉鐖剁骇涓媍hildren鐨刲ength涓�1锛屽垹闄hildren骞惰嚜鍔ㄧ粍寤哄敮涓�uniqueId + * @param tree 鏍� + * @param pathList 姣忎竴椤圭殑id缁勬垚鐨勬暟缁� + * @returns 缁勪欢鍞竴uniqueId鍚庣殑鏍� + */ +export const deleteChildren = (tree: any[], pathList = []): any => { + if (!Array.isArray(tree)) { + console.warn("menuTree must be an array"); + return []; + } + if (!tree || tree.length === 0) return []; + for (const [key, node] of tree.entries()) { + if (node.children && node.children.length === 1) delete node.children; + node.id = key; + node.parentId = pathList.length ? pathList[pathList.length - 1] : null; + node.pathList = [...pathList, node.id]; + node.uniqueId = + node.pathList.length > 1 ? node.pathList.join("-") : node.pathList[0]; + const hasChildren = node.children && node.children.length > 0; + if (hasChildren) { + deleteChildren(node.children, node.pathList); + } + } + return tree; +}; + +/** + * @description 鍒涘缓灞傜骇鍏崇郴 + * @param tree 鏍� + * @param pathList 姣忎竴椤圭殑id缁勬垚鐨勬暟缁� + * @returns 鍒涘缓灞傜骇鍏崇郴鍚庣殑鏍� + */ +export const buildHierarchyTree = (tree: any[], pathList = []): any => { + if (!Array.isArray(tree)) { + console.warn("tree must be an array"); + return []; + } + if (!tree || tree.length === 0) return []; + for (const [key, node] of tree.entries()) { + node.id = key; + node.parentId = pathList.length ? pathList[pathList.length - 1] : null; + node.pathList = [...pathList, node.id]; + const hasChildren = node.children && node.children.length > 0; + if (hasChildren) { + buildHierarchyTree(node.children, node.pathList); + } + } + return tree; +}; + +/** + * @description 骞垮害浼樺厛閬嶅巻锛屾牴鎹敮涓�uniqueId鎵惧綋鍓嶈妭鐐逛俊鎭� + * @param tree 鏍� + * @param uniqueId 鍞竴uniqueId + * @returns 褰撳墠鑺傜偣淇℃伅 + */ +export const getNodeByUniqueId = ( + tree: any[], + uniqueId: number | string +): any => { + if (!Array.isArray(tree)) { + console.warn("menuTree must be an array"); + return []; + } + if (!tree || tree.length === 0) return []; + const item = tree.find(node => node.uniqueId === uniqueId); + if (item) return item; + const childrenList = tree + .filter(node => node.children) + .map(i => i.children) + .flat(1) as unknown; + return getNodeByUniqueId(childrenList as any[], uniqueId); +}; + +/** + * @description 鍚戝綋鍓嶅敮涓�uniqueId鑺傜偣涓拷鍔犲瓧娈� + * @param tree 鏍� + * @param uniqueId 鍞竴uniqueId + * @param fields 闇�瑕佽拷鍔犵殑瀛楁 + * @returns 杩藉姞瀛楁鍚庣殑鏍� + */ +export const appendFieldByUniqueId = ( + tree: any[], + uniqueId: number | string, + fields: object +): any => { + if (!Array.isArray(tree)) { + console.warn("menuTree must be an array"); + return []; + } + if (!tree || tree.length === 0) return []; + for (const node of tree) { + const hasChildren = node.children && node.children.length > 0; + if ( + node.uniqueId === uniqueId && + Object.prototype.toString.call(fields) === "[object Object]" + ) + Object.assign(node, fields); + if (hasChildren) { + appendFieldByUniqueId(node.children, uniqueId, fields); + } + } + return tree; +}; + +/** + * @description 鏋勯�犳爲鍨嬬粨鏋勬暟鎹� + * @param data 鏁版嵁婧� + * @param id id瀛楁 榛樿id + * @param parentId 鐖惰妭鐐瑰瓧娈碉紝榛樿parentId + * @param children 瀛愯妭鐐瑰瓧娈碉紝榛樿children + * @returns 杩藉姞瀛楁鍚庣殑鏍� + */ +export const handleTree = ( + data: any[], + id?: string, + parentId?: string, + children?: string +): any => { + if (!Array.isArray(data)) { + console.warn("data must be an array"); + return []; + } + const config = { + id: id || "id", + parentId: parentId || "parentId", + childrenList: children || "children" + }; + + const childrenListMap: any = {}; + const nodeIds: any = {}; + const tree = []; + + for (const d of data) { + const parentId = d[config.parentId]; + if (childrenListMap[parentId] == null) { + childrenListMap[parentId] = []; + } + nodeIds[d[config.id]] = d; + childrenListMap[parentId].push(d); + } + + for (const d of data) { + const parentId = d[config.parentId]; + if (nodeIds[parentId] == null) { + tree.push(d); + } + } + + for (const t of tree) { + adaptToChildrenList(t); + } + + function adaptToChildrenList(o: Record<string, any>) { + if (childrenListMap[o[config.id]] !== null) { + o[config.childrenList] = childrenListMap[o[config.id]]; + } + if (o[config.childrenList]) { + for (const c of o[config.childrenList]) { + adaptToChildrenList(c); + } + } + } + return tree; +}; diff --git a/src/views/error/403.vue b/src/views/error/403.vue new file mode 100644 index 0000000..ffd9df4 --- /dev/null +++ b/src/views/error/403.vue @@ -0,0 +1,70 @@ +<script setup lang="ts"> +import { useRouter } from "vue-router"; +import noAccess from "@/assets/status/403.svg?component"; + +defineOptions({ + name: "403" +}); + +const router = useRouter(); +</script> + +<template> + <div class="flex justify-center items-center h-[640px]"> + <noAccess /> + <div class="ml-12"> + <p + v-motion + class="font-medium text-4xl mb-4! dark:text-white" + :initial="{ + opacity: 0, + y: 100 + }" + :enter="{ + opacity: 1, + y: 0, + transition: { + delay: 80 + } + }" + > + 403 + </p> + <p + v-motion + class="mb-4! text-gray-500" + :initial="{ + opacity: 0, + y: 100 + }" + :enter="{ + opacity: 1, + y: 0, + transition: { + delay: 120 + } + }" + > + 鎶辨瓑锛屼綘鏃犳潈璁块棶璇ラ〉闈� + </p> + <el-button + v-motion + type="primary" + :initial="{ + opacity: 0, + y: 100 + }" + :enter="{ + opacity: 1, + y: 0, + transition: { + delay: 160 + } + }" + @click="router.push('/')" + > + 杩斿洖棣栭〉 + </el-button> + </div> + </div> +</template> diff --git a/src/views/error/404.vue b/src/views/error/404.vue new file mode 100644 index 0000000..44ecf14 --- /dev/null +++ b/src/views/error/404.vue @@ -0,0 +1,70 @@ +<script setup lang="ts"> +import { useRouter } from "vue-router"; +import noExist from "@/assets/status/404.svg?component"; + +defineOptions({ + name: "404" +}); + +const router = useRouter(); +</script> + +<template> + <div class="flex justify-center items-center h-[640px]"> + <noExist /> + <div class="ml-12"> + <p + v-motion + class="font-medium text-4xl mb-4! dark:text-white" + :initial="{ + opacity: 0, + y: 100 + }" + :enter="{ + opacity: 1, + y: 0, + transition: { + delay: 80 + } + }" + > + 404 + </p> + <p + v-motion + class="mb-4! text-gray-500" + :initial="{ + opacity: 0, + y: 100 + }" + :enter="{ + opacity: 1, + y: 0, + transition: { + delay: 120 + } + }" + > + 鎶辨瓑锛屼綘璁块棶鐨勯〉闈笉瀛樺湪 + </p> + <el-button + v-motion + type="primary" + :initial="{ + opacity: 0, + y: 100 + }" + :enter="{ + opacity: 1, + y: 0, + transition: { + delay: 160 + } + }" + @click="router.push('/')" + > + 杩斿洖棣栭〉 + </el-button> + </div> + </div> +</template> diff --git a/src/views/error/500.vue b/src/views/error/500.vue new file mode 100644 index 0000000..cd24409 --- /dev/null +++ b/src/views/error/500.vue @@ -0,0 +1,70 @@ +<script setup lang="ts"> +import { useRouter } from "vue-router"; +import noServer from "@/assets/status/500.svg?component"; + +defineOptions({ + name: "500" +}); + +const router = useRouter(); +</script> + +<template> + <div class="flex justify-center items-center h-[640px]"> + <noServer /> + <div class="ml-12"> + <p + v-motion + class="font-medium text-4xl mb-4! dark:text-white" + :initial="{ + opacity: 0, + y: 100 + }" + :enter="{ + opacity: 1, + y: 0, + transition: { + delay: 80 + } + }" + > + 500 + </p> + <p + v-motion + class="mb-4! text-gray-500" + :initial="{ + opacity: 0, + y: 100 + }" + :enter="{ + opacity: 1, + y: 0, + transition: { + delay: 120 + } + }" + > + 鎶辨瓑锛屾湇鍔″櫒鍑洪敊浜� + </p> + <el-button + v-motion + type="primary" + :initial="{ + opacity: 0, + y: 100 + }" + :enter="{ + opacity: 1, + y: 0, + transition: { + delay: 160 + } + }" + @click="router.push('/')" + > + 杩斿洖棣栭〉 + </el-button> + </div> + </div> +</template> diff --git a/src/views/home/index.vue b/src/views/home/index.vue new file mode 100644 index 0000000..566fbae --- /dev/null +++ b/src/views/home/index.vue @@ -0,0 +1,510 @@ +<template> + <div class="header"> + <img width="227px" height="74px" src="@/assets/home/logo.png" alt="" /> + <img width="427px" height="74px" src="@/assets/home/Header.png" alt="" /> + <div class="other"> + <div class="item"> + <img width="21px" height="21px" src="@/assets/home/share.png" alt="" /> + <span>鍒嗕韩缃戠珯</span> + </div> + <div class="item"> + <img + width="21px" + height="21px" + src="@/assets/home/BellFilled.png" + alt="" + /> + <span>鎴戠殑娑堟伅</span> + </div> + </div> + </div> + <div class="banner"> + <img width="100%" src="@/assets/home/banner.png" alt="" /> + </div> + <div class="notice"> + <div class="left"> + <div class="item item1"> + <div style='width:50%'> + <img src="@/assets/home/notice1.png" alt="" /> + </div> + <div>鎷涢噰鍏憡</div> + </div> + <div class="item"> + <img src="@/assets/home/notice.png" alt="" /> + <div>鎷涢噰鍏憡</div> + </div> + <div class="item"> + <img src="@/assets/home/notice.png" alt="" /> + <div>鎷涢噰鍏憡</div> + </div> + <div class="item"> + <img src="@/assets/home/notice.png" alt="" /> + <div>鎷涢噰鍏憡</div> + </div> + </div> + <div class="right"> + <el-tabs v-model="activeName" class="demo-tabs"> + <el-tab-pane label="宸ョ▼鎷涙爣" name="first"> + <div class="item"> + <span + ><span style="color: #145ccd; font-weight: 600">路</span + >銆愬洓宸濈渷鎴愰兘甯傘��2024骞寸煶鐩樿閬撲粯瀹剁鏉戠伯娌逛骇涓氬洯鍖哄強閰嶅鍩虹璁炬柦寤鸿椤圭洰纾嬪晢鍏憡</span + > + <span>2024-04-15 18:10</span> + </div> + <div class="item"> + <span + ><span style="color: #145ccd; font-weight: 600">路</span + >銆愬洓宸濈渷鎴愰兘甯傘�戠唺鐚胺娓稿涓績灞�閮ㄦ敼閫犻」鐩鍟嗗叕鍛�</span + > + <span>2024-04-15 18:10</span> + </div> + <div class="item"> + <span + ><span style="color: #145ccd; font-weight: 600">路</span + >銆愬洓宸濈渷鎴愰兘甯傘�戜腹鏅閬撴皯婀栫ぞ鍖虹孩鐧藉枩浜嬫湇鍔″満鎵�纾嬪晢鍏憡</span + > + <span>2024-04-15 18:10</span> + </div> + <div class="item"> + <span + ><span style="color: #145ccd; font-weight: 600">路</span + >銆愬洓宸濈渷鎴愰兘甯傘�戞垚閮戒笢閮ㄦ柊鍖轰笁宀旀箹楂樼骇涓浣撹壓涓績鍓嶄复鏃跺仠杞﹀尯鍜屾鏍¢棬涓や晶闂ㄥ崼瀹ら棿鍖哄煙榛戝寲鍙婃帓姘存彁鍗囪В闄ゅ唴娑濋」鐩鍟嗗叕鍛�</span + > + <span>2024-04-15 18:10</span> + </div> + <div class="item"> + <span + ><span style="color: #145ccd; font-weight: 600">路</span + >銆愬洓宸濈渷鎴愰兘甯傘�戝洓宸濈渷鎴愰兘鎴掓瘨搴峰鎵�鐥呮畫鎴掓瘨浜哄憳搴峰娲诲姩涓績缁翠慨鏀归�犻」鐩浜屾纾嬪晢鍏憡</span + > + <span>2024-04-15 18:10</span> + </div> + <div class="item"> + <span + ><span style="color: #145ccd; font-weight: 600">路</span + >銆愬洓宸濈渷鎴愰兘甯傘�戣�佸共閮ㄦ椿鍔ㄤ腑蹇冭淇敼閫犻」鐩鍟嗗叕鍛�</span + > + <span>2024-04-15 18:10</span> + </div> + <div class="item"> + <span + ><span style="color: #145ccd; font-weight: 600">路</span + >銆愬洓宸濈渷鎴愰兘甯傘�戦噾鐗涘尯鎶㈤櫓鏁戠伨宸ョ▼椤圭洰宸ョ▼闃熶紞鍌ㄥ搴擄紙鎴垮缓銆佸競鏀跨被锛夋嫑鏍囧叕鍛�</span + > + <span>2024-04-15 18:10</span> + </div> + </el-tab-pane> + <el-tab-pane label="璐х墿鎷涙爣" name="second">璐х墿鎷涙爣</el-tab-pane> + <el-tab-pane label="鏈嶅姟鎷涙爣" name="third">鏈嶅姟鎷涙爣</el-tab-pane> + <el-tab-pane label="缃戜笂绔炰环" name="fourth">缃戜笂绔炰环</el-tab-pane> + </el-tabs> + </div> + </div> + <div class="user"> + <div class="all"> + <div class="left"> + <div class="item item1"> + <div class="box"> + <img + width="18px" + height="18px" + src="@/assets/home/car1.png" + alt="" + /> + 閲囪喘浜�/鎷涙爣浜� + </div> + <span>娉ㄥ唽|鐧诲綍</span> + </div> + <div class="item"> + <div class="box"> + <img + width="18px" + height="18px" + src="@/assets/home/car.png" + alt="" + /> + 閲囪喘浜� + </div> + <span>娉ㄥ唽|鐧诲綍</span> + </div> + <div class="item"> + <div class="box"> + <img + width="18px" + height="18px" + src="@/assets/home/car.png" + alt="" + />鎷涙爣浠g悊鏈烘瀯 + </div> + <span>娉ㄥ唽|鐧诲綍</span> + </div> + <div class="item"> + <div class="box"> + <img + width="18px" + height="18px" + src="@/assets/home/car.png" + alt="" + />渚涘簲鍟� + </div> + <span>娉ㄥ唽|鐧诲綍</span> + </div> + <div class="item"> + <div class="box"> + <img + width="18px" + height="18px" + src="@/assets/home/car.png" + alt="" + />璇勫涓撳 + </div> + <span>娉ㄥ唽|鐧诲綍</span> + </div> + </div> + <div class="right"></div> + </div> + </div> + <div class="daixie"> + <div class="content"> + <div class="item"> + <img src="@/assets/home/daixie.png" alt="" /> + <span>鏍囦功浠e啓</span> + </div> + <div class="item"> + <img src="@/assets/home/daixie.png" alt="" /> + <span>璧勮川璇佷功浠e姙</span> + </div> + <div class="item"> + <img src="@/assets/home/daixie.png" alt="" /> + <span>鎷涙爣閲戦</span> + </div> + <div class="item"> + <img src="@/assets/home/daixie.png" alt="" /> + <span>娉曞緥鏈嶅姟</span> + </div> + <div class="item"> + <img src="@/assets/home/daixie.png" alt="" /> + <span>骞冲彴寮�鍙�</span> + </div> + <div class="item"> + <img src="@/assets/home/daixie.png" alt="" /> + <span>鍏紬鍙疯繍钀�</span> + </div> + </div> + </div> + <div class="more"> + <div class="content"> + <div class="item"> + <div class="header"> + <div + style="display: flex; align-items: center; justify-content: center" + > + <img src="@/assets/home/xian.png" alt="" /> + <span style="margin-left: 5px">琛屼笟鍔ㄦ��</span> + </div> + <el-button round + >鏇村<el-icon class="el-icon--right" + ><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"> + <path + fill="currentColor" + d="M480 480V128a32 32 0 0 1 64 0v352h352a32 32 0 1 1 0 64H544v352a32 32 0 1 1-64 0V544H128a32 32 0 0 1 0-64z" + ></path></svg></el-icon + ></el-button> + </div> + <div class="main"> + <div class="img"></div> + <div class="right"> + <p>鍥藉鍙戝睍鏀归潻濮斿姙鍏巺鍏充簬瑙勮寖鎷涙爣鎶曟爣棰嗗煙淇$敤璇勪环搴旂敤鐨勯�氱煡</p> + <p class="time">2025-05-22</p> + </div> + </div> + <div class="other"> + <div class="item"> + <span + ><span style="color: #145ccd; font-weight: 600">路</span + >鍥藉鍙戝睍鏀归潻濮斿姙鍏巺鍏充簬瑙勮寖鎷涙爣鎶暵仿仿�</span + > + <span class="time">05-22</span> + </div> + </div> + </div> + <div class="item"></div> + <div class="item"></div> + </div> + </div> +</template> + +<script lang="ts" setup> +import { ref } from "vue"; +let activeName = ref("first"); +</script> + +<style lang="scss" scoped> +.header { + display: flex; + align-items: center; + justify-content: space-evenly; + height: 80px; + width: 100%; + .middle { + width: 50%; + display: flex; + justify-content: space-around; + color: rgb(51, 51, 51); + font-family: 鎬濇簮榛戜綋; + } + .other { + display: flex; + .item { + display: flex; + justify-content: center; + width: 63px; + height: 48px; + color: rgb(51, 51, 51); + font-family: 鎬濇簮榛戜綋; + font-size: 12px; + font-weight: 400; + line-height: 20px; + letter-spacing: 0%; + text-align: left; + text-transform: capitalize; + flex-wrap: wrap; + margin-right: 10px; + } + } +} +.banner { + // left: -3.76px; + // top: 80px; + // position: absolute; + width: 100%; + height: 306px; +} +.notice { + box-sizing: border-box; + display: flex; + justify-content: space-between; + width: 1401px; + height: 518px; + padding: 15px; + margin: 20px auto; + background: rgb(254, 254, 254); + border-radius: 8px; + box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px; + .left { + width: 10%; + height: 483px; + display: flex; + flex-wrap: wrap; + justify-content: space-between; + .item { + width: 137px; + height: 111px; + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + background: rgb(244, 244, 244); + border-radius: 6px; + img { + width: 30px; + height: 30px; + } + div { + // display: block; + // width: 100%; + color: rgb(20, 92, 205); + font-size: 20px; + font-weight: 500; + align-items: center; + } + } + .item1 { + background: rgb(20, 92, 205); + div { + color: rgb(254, 254, 254); + } + } + } + .right { + width: 89%; + height: 51px; + border-radius: 4px; + .item { + // height: 51px; + line-height: 51px; + display: flex; + justify-content: space-between; + padding: 0 10px; + } + /* 鍋舵暟琛岃儗鏅壊 */ + .item:nth-child(even) { + background: rgb(244, 244, 244); + border-radius: 4px; + } + /* 濂囨暟琛岃儗鏅壊 */ + .item:nth-child(odd) { + padding: 8px; + background-color: #fff; + } + } +} +.user { + width: 100%; + height: 520px; + background: rgb(248, 248, 248); + padding-top: 50px; + .all { + width: 1401px; + height: 482px; + background: #fff; + margin: 0 auto; + display: flex; + justify-content: space-between; + border-radius: 8px; + + .left { + box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px; + width: 23%; + height: 100%; + border-radius: 8px; + .item { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 50px; + height: 20%; + text-align: left; + color: #5f5f5f; + .box { + display: flex; + justify-content: center; + align-items: center; + } + img { + margin-right: 5px; + } + } + .item1 { + background: #1a67e3; + color: #ffffff; + } + } + .left :first-child { + border-top-left-radius: 8px; + border-top-right-radius: 8px; + } + .left *:not(:first-child):not(:last-child) { + border-bottom: #c6c6c6 1px solid; + } + .right { + background: #a9b3c4; + width: 75%; + height: 100%; + border-radius: 8px; + } + } +} +.daixie { + width: 100%; + background: #fff; + .content { + width: 1401px; + height: 140px; + padding: 20px 0; + margin: 0 auto; + display: flex; + justify-content: space-around; + .item { + width: 13%; + display: flex; + flex-wrap: wrap; + justify-content: center; + span { + color: rgb(95, 95, 95); + font-family: 鎬濇簮榛戜綋; + font-size: 24px; + font-weight: 500; + line-height: 40.8px; + letter-spacing: 1%; + text-align: center; + text-transform: capitalize; + display: flex; + flex-direction: row; + align-items: center; + } + } + img { + width: 100px; + height: 106px; + } + } +} +.more { + width: 100%; + height: 464px; + background: #f8f8f8; + padding-top: 50px; + .time { + color: rgb(152, 152, 152); + font-family: Figtree; + font-size: 15px; + font-weight: 400; + line-height: 24.2px; + } + .content { + width: 1400px; + height: 415px; + background: cadetblue; + margin: 0 auto; + display: flex; + justify-content: space-between; + .item { + background: #fff; + width: 28%; + height: 100%; + border-radius: 8px; + padding: 20px; + .header { + height: 41px; + color: rgb(0, 0, 0); + font-family: 鎬濇簮榛戜綋; + font-size: 24px; + font-weight: 500; + display: flex; + align-items: center; + justify-content: space-between; + } + .main { + display: flex; + align-items: center; + justify-content: space-between; + flex: 1; + .img { + width: 142px; + height: 95px; + background: rgb(196, 196, 196); + border-radius: 4px; + } + .right { + width: 240px; + color: rgb(95, 95, 95); + font-family: 鎬濇簮榛戜綋; + font-size: 16px; + font-weight: 400; + line-height: 24.2px; + text-align: left; + margin-left: 10px; + } + } + .other { + width: 100%; + .item { + width: 100%; + } + } + } + } +} +</style> diff --git a/src/views/login/index.vue b/src/views/login/index.vue new file mode 100644 index 0000000..732463a --- /dev/null +++ b/src/views/login/index.vue @@ -0,0 +1,180 @@ +<script setup lang="ts"> +import Motion from "./utils/motion"; +import { useRouter } from "vue-router"; +import { message } from "@/utils/message"; +import { loginRules } from "./utils/rule"; +import { ref, reactive, toRaw } from "vue"; +import { debounce } from "@pureadmin/utils"; +import { useNav } from "@/layout/hooks/useNav"; +import { useEventListener } from "@vueuse/core"; +import type { FormInstance } from "element-plus"; +import { useLayout } from "@/layout/hooks/useLayout"; +import { useUserStoreHook } from "@/store/modules/user"; +import { initRouter, getTopMenu } from "@/router/utils"; +import { bg, avatar, illustration } from "./utils/static"; +import { useRenderIcon } from "@/components/ReIcon/src/hooks"; +import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange"; + +import dayIcon from "@/assets/svg/day.svg?component"; +import darkIcon from "@/assets/svg/dark.svg?component"; +import Lock from "~icons/ri/lock-fill"; +import User from "~icons/ri/user-3-fill"; + +defineOptions({ + name: "Login" +}); + +const router = useRouter(); +const loading = ref(false); +const disabled = ref(false); +const ruleFormRef = ref<FormInstance>(); + +const { initStorage } = useLayout(); +initStorage(); + +const { dataTheme, overallStyle, dataThemeChange } = useDataThemeChange(); +dataThemeChange(overallStyle.value); +const { title } = useNav(); + +const ruleForm = reactive({ + username: "admin", + password: "admin123" +}); + +const onLogin = async (formEl: FormInstance | undefined) => { + if (!formEl) return; + await formEl.validate(valid => { + if (valid) { + loading.value = true; + useUserStoreHook() + .loginByUsername({ + username: ruleForm.username, + password: ruleForm.password + }) + .then(res => { + if (res.success) { + // 鑾峰彇鍚庣璺敱 + return initRouter().then(() => { + disabled.value = true; + router + .push(getTopMenu(true).path) + .then(() => { + message("鐧诲綍鎴愬姛", { type: "success" }); + }) + .finally(() => (disabled.value = false)); + }); + } else { + message("鐧诲綍澶辫触", { type: "error" }); + } + }) + .finally(() => (loading.value = false)); + } + }); +}; + +const immediateDebounce: any = debounce( + formRef => onLogin(formRef), + 1000, + true +); + +useEventListener(document, "keydown", ({ code }) => { + if ( + ["Enter", "NumpadEnter"].includes(code) && + !disabled.value && + !loading.value + ) + immediateDebounce(ruleFormRef.value); +}); +</script> + +<template> + <div class="select-none"> + <img :src="bg" class="wave" /> + <div class="flex-c absolute right-5 top-3"> + <!-- 涓婚 --> + <el-switch + v-model="dataTheme" + inline-prompt + :active-icon="dayIcon" + :inactive-icon="darkIcon" + @change="dataThemeChange" + /> + </div> + <div class="login-container"> + <div class="img"> + <component :is="toRaw(illustration)" /> + </div> + <div class="login-box"> + <div class="login-form"> + <avatar class="avatar" /> + <Motion> + <h2 class="outline-hidden">{{ title }}</h2> + </Motion> + + <el-form + ref="ruleFormRef" + :model="ruleForm" + :rules="loginRules" + size="large" + > + <Motion :delay="100"> + <el-form-item + :rules="[ + { + required: true, + message: '璇疯緭鍏ヨ处鍙�', + trigger: 'blur' + } + ]" + prop="username" + > + <el-input + v-model="ruleForm.username" + clearable + placeholder="璐﹀彿" + :prefix-icon="useRenderIcon(User)" + /> + </el-form-item> + </Motion> + + <Motion :delay="150"> + <el-form-item prop="password"> + <el-input + v-model="ruleForm.password" + clearable + show-password + placeholder="瀵嗙爜" + :prefix-icon="useRenderIcon(Lock)" + /> + </el-form-item> + </Motion> + + <Motion :delay="250"> + <el-button + class="w-full mt-4!" + size="default" + type="primary" + :loading="loading" + :disabled="disabled" + @click="onLogin(ruleFormRef)" + > + 鐧诲綍 + </el-button> + </Motion> + </el-form> + </div> + </div> + </div> + </div> +</template> + +<style scoped> +@import url("@/style/login.css"); +</style> + +<style lang="scss" scoped> +:deep(.el-input-group__append, .el-input-group__prepend) { + padding: 0; +} +</style> diff --git a/src/views/login/utils/motion.ts b/src/views/login/utils/motion.ts new file mode 100644 index 0000000..2b1182c --- /dev/null +++ b/src/views/login/utils/motion.ts @@ -0,0 +1,40 @@ +import { h, defineComponent, withDirectives, resolveDirective } from "vue"; + +/** 灏佽@vueuse/motion鍔ㄧ敾搴撲腑鐨勮嚜瀹氫箟鎸囦护v-motion */ +export default defineComponent({ + name: "Motion", + props: { + delay: { + type: Number, + default: 50 + } + }, + render() { + const { delay } = this; + const motion = resolveDirective("motion"); + return withDirectives( + h( + "div", + {}, + { + default: () => [this.$slots.default()] + } + ), + [ + [ + motion, + { + initial: { opacity: 0, y: 100 }, + enter: { + opacity: 1, + y: 0, + transition: { + delay + } + } + } + ] + ] + ); + } +}); diff --git a/src/views/login/utils/rule.ts b/src/views/login/utils/rule.ts new file mode 100644 index 0000000..b32982c --- /dev/null +++ b/src/views/login/utils/rule.ts @@ -0,0 +1,28 @@ +import { reactive } from "vue"; +import type { FormRules } from "element-plus"; + +/** 瀵嗙爜姝e垯锛堝瘑鐮佹牸寮忓簲涓�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}$/; + +/** 鐧诲綍鏍¢獙 */ +const loginRules = reactive<FormRules>({ + password: [ + { + validator: (rule, value, callback) => { + if (value === "") { + callback(new Error("璇疯緭鍏ュ瘑鐮�")); + } else if (!REGEXP_PWD.test(value)) { + callback( + new Error("瀵嗙爜鏍煎紡搴斾负8-18浣嶆暟瀛椼�佸瓧姣嶃�佺鍙风殑浠绘剰涓ょ缁勫悎") + ); + } else { + callback(); + } + }, + trigger: "blur" + } + ] +}); + +export { loginRules }; diff --git a/src/views/login/utils/static.ts b/src/views/login/utils/static.ts new file mode 100644 index 0000000..18268d8 --- /dev/null +++ b/src/views/login/utils/static.ts @@ -0,0 +1,5 @@ +import bg from "@/assets/login/bg.png"; +import avatar from "@/assets/login/avatar.svg?component"; +import illustration from "@/assets/login/illustration.svg?component"; + +export { bg, avatar, illustration }; diff --git a/src/views/permission/button/index.vue b/src/views/permission/button/index.vue new file mode 100644 index 0000000..5053e0a --- /dev/null +++ b/src/views/permission/button/index.vue @@ -0,0 +1,99 @@ +<script setup lang="ts"> +import { hasAuth, getAuths } from "@/router/utils"; + +defineOptions({ + name: "PermissionButtonRouter" +}); +</script> + +<template> + <div> + <p class="mb-2!">褰撳墠鎷ユ湁鐨刢ode鍒楄〃锛歿{ getAuths() }}</p> + + <el-card shadow="never" class="mb-2"> + <template #header> + <div class="card-header">缁勪欢鏂瑰紡鍒ゆ柇鏉冮檺</div> + </template> + <el-space wrap> + <Auth value="permission:btn:add"> + <el-button plain type="warning"> + 鎷ユ湁code锛�'permission:btn:add' 鏉冮檺鍙 + </el-button> + </Auth> + <Auth :value="['permission:btn:edit']"> + <el-button plain type="primary"> + 鎷ユ湁code锛歔'permission:btn:edit'] 鏉冮檺鍙 + </el-button> + </Auth> + <Auth + :value="[ + 'permission:btn:add', + 'permission:btn:edit', + 'permission:btn:delete' + ]" + > + <el-button plain type="danger"> + 鎷ユ湁code锛歔'permission:btn:add', 'permission:btn:edit', + 'permission:btn:delete'] 鏉冮檺鍙 + </el-button> + </Auth> + </el-space> + </el-card> + + <el-card shadow="never" class="mb-2"> + <template #header> + <div class="card-header">鍑芥暟鏂瑰紡鍒ゆ柇鏉冮檺</div> + </template> + <el-space wrap> + <el-button v-if="hasAuth('permission:btn:add')" plain type="warning"> + 鎷ユ湁code锛�'permission:btn:add' 鏉冮檺鍙 + </el-button> + <el-button v-if="hasAuth(['permission:btn:edit'])" plain type="primary"> + 鎷ユ湁code锛歔'permission:btn:edit'] 鏉冮檺鍙 + </el-button> + <el-button + v-if=" + hasAuth([ + 'permission:btn:add', + 'permission:btn:edit', + 'permission:btn:delete' + ]) + " + plain + type="danger" + > + 鎷ユ湁code锛歔'permission:btn:add', 'permission:btn:edit', + 'permission:btn:delete'] 鏉冮檺鍙 + </el-button> + </el-space> + </el-card> + + <el-card shadow="never"> + <template #header> + <div class="card-header"> + 鎸囦护鏂瑰紡鍒ゆ柇鏉冮檺锛堣鏂瑰紡涓嶈兘鍔ㄦ�佷慨鏀规潈闄愶級 + </div> + </template> + <el-space wrap> + <el-button v-auth="'permission:btn:add'" plain type="warning"> + 鎷ユ湁code锛�'permission:btn:add' 鏉冮檺鍙 + </el-button> + <el-button v-auth="['permission:btn:edit']" plain type="primary"> + 鎷ユ湁code锛歔'permission:btn:edit'] 鏉冮檺鍙 + </el-button> + <el-button + v-auth="[ + 'permission:btn:add', + 'permission:btn:edit', + 'permission:btn:delete' + ]" + plain + type="danger" + > + 鎷ユ湁code锛歔'permission:btn:add', 'permission:btn:edit', + 'permission:btn:delete'] 鏉冮檺鍙 + </el-button> + </el-space> + </el-card> + </div> +</template> diff --git a/src/views/permission/button/perms.vue b/src/views/permission/button/perms.vue new file mode 100644 index 0000000..8fce6da --- /dev/null +++ b/src/views/permission/button/perms.vue @@ -0,0 +1,109 @@ +<script setup lang="ts"> +import { hasPerms } from "@/utils/auth"; +import { useUserStoreHook } from "@/store/modules/user"; + +const { permissions } = useUserStoreHook(); + +defineOptions({ + name: "PermissionButtonLogin" +}); +</script> + +<template> + <div> + <p class="mb-2!">褰撳墠鎷ユ湁鐨刢ode鍒楄〃锛歿{ permissions }}</p> + <p v-show="permissions?.[0] === '*:*:*'" class="mb-2!"> + *:*:* 浠h〃鎷ユ湁鍏ㄩ儴鎸夐挳绾у埆鏉冮檺 + </p> + + <el-card shadow="never" class="mb-2"> + <template #header> + <div class="card-header">缁勪欢鏂瑰紡鍒ゆ柇鏉冮檺</div> + </template> + <el-space wrap> + <Perms value="permission:btn:add"> + <el-button plain type="warning"> + 鎷ユ湁code锛�'permission:btn:add' 鏉冮檺鍙 + </el-button> + </Perms> + <Perms :value="['permission:btn:edit']"> + <el-button plain type="primary"> + 鎷ユ湁code锛歔'permission:btn:edit'] 鏉冮檺鍙 + </el-button> + </Perms> + <Perms + :value="[ + 'permission:btn:add', + 'permission:btn:edit', + 'permission:btn:delete' + ]" + > + <el-button plain type="danger"> + 鎷ユ湁code锛歔'permission:btn:add', 'permission:btn:edit', + 'permission:btn:delete'] 鏉冮檺鍙 + </el-button> + </Perms> + </el-space> + </el-card> + + <el-card shadow="never" class="mb-2"> + <template #header> + <div class="card-header">鍑芥暟鏂瑰紡鍒ゆ柇鏉冮檺</div> + </template> + <el-space wrap> + <el-button v-if="hasPerms('permission:btn:add')" plain type="warning"> + 鎷ユ湁code锛�'permission:btn:add' 鏉冮檺鍙 + </el-button> + <el-button + v-if="hasPerms(['permission:btn:edit'])" + plain + type="primary" + > + 鎷ユ湁code锛歔'permission:btn:edit'] 鏉冮檺鍙 + </el-button> + <el-button + v-if=" + hasPerms([ + 'permission:btn:add', + 'permission:btn:edit', + 'permission:btn:delete' + ]) + " + plain + type="danger" + > + 鎷ユ湁code锛歔'permission:btn:add', 'permission:btn:edit', + 'permission:btn:delete'] 鏉冮檺鍙 + </el-button> + </el-space> + </el-card> + + <el-card shadow="never"> + <template #header> + <div class="card-header"> + 鎸囦护鏂瑰紡鍒ゆ柇鏉冮檺锛堣鏂瑰紡涓嶈兘鍔ㄦ�佷慨鏀规潈闄愶級 + </div> + </template> + <el-space wrap> + <el-button v-perms="'permission:btn:add'" plain type="warning"> + 鎷ユ湁code锛�'permission:btn:add' 鏉冮檺鍙 + </el-button> + <el-button v-perms="['permission:btn:edit']" plain type="primary"> + 鎷ユ湁code锛歔'permission:btn:edit'] 鏉冮檺鍙 + </el-button> + <el-button + v-perms="[ + 'permission:btn:add', + 'permission:btn:edit', + 'permission:btn:delete' + ]" + plain + type="danger" + > + 鎷ユ湁code锛歔'permission:btn:add', 'permission:btn:edit', + 'permission:btn:delete'] 鏉冮檺鍙 + </el-button> + </el-space> + </el-card> + </div> +</template> diff --git a/src/views/permission/page/index.vue b/src/views/permission/page/index.vue new file mode 100644 index 0000000..13703df --- /dev/null +++ b/src/views/permission/page/index.vue @@ -0,0 +1,66 @@ +<script setup lang="ts"> +import { initRouter } from "@/router/utils"; +import { storageLocal } from "@pureadmin/utils"; +import { type CSSProperties, ref, computed } from "vue"; +import { useUserStoreHook } from "@/store/modules/user"; +import { usePermissionStoreHook } from "@/store/modules/permission"; + +defineOptions({ + name: "PermissionPage" +}); + +const elStyle = computed((): CSSProperties => { + return { + width: "85vw", + justifyContent: "start" + }; +}); + +const username = ref(useUserStoreHook()?.username); + +const options = [ + { + value: "admin", + label: "绠$悊鍛樿鑹�" + }, + { + value: "common", + label: "鏅�氳鑹�" + } +]; + +function onChange() { + useUserStoreHook() + .loginByUsername({ username: username.value, password: "admin123" }) + .then(res => { + if (res.success) { + storageLocal().removeItem("async-routes"); + usePermissionStoreHook().clearAllCachePage(); + initRouter(); + } + }); +} +</script> + +<template> + <div> + <p class="mb-2!"> + 妯℃嫙鍚庡彴鏍规嵁涓嶅悓瑙掕壊杩斿洖瀵瑰簲璺敱锛岃瀵熷乏渚ц彍鍗曞彉鍖栵紙绠$悊鍛樿鑹插彲鏌ョ湅绯荤粺绠$悊鑿滃崟銆佹櫘閫氳鑹蹭笉鍙煡鐪嬬郴缁熺鐞嗚彍鍗曪級 + </p> + <el-card shadow="never" :style="elStyle"> + <template #header> + <div class="card-header"> + <span>褰撳墠瑙掕壊锛歿{ username }}</span> + </div> + </template> + <el-select v-model="username" class="w-[160px]!" @change="onChange"> + <el-option + v-for="item in options" + :key="item.value" + :label="item.label" + :value="item.value" + /> + </el-select> + </el-card> + </div> +</template> diff --git a/src/views/welcome/index.vue b/src/views/welcome/index.vue new file mode 100644 index 0000000..8db10d2 --- /dev/null +++ b/src/views/welcome/index.vue @@ -0,0 +1,9 @@ +<script setup lang="ts"> +defineOptions({ + name: "Welcome" +}); +</script> + +<template> + <h1>Pure-Admin-Thin锛堥潪鍥介檯鍖栫増鏈級</h1> +</template> diff --git a/stylelint.config.js b/stylelint.config.js new file mode 100644 index 0000000..2417ddf --- /dev/null +++ b/stylelint.config.js @@ -0,0 +1,87 @@ +// @ts-check + +/** @type {import("stylelint").Config} */ +export default { + extends: [ + "stylelint-config-standard", + "stylelint-config-html/vue", + "stylelint-config-recess-order" + ], + plugins: ["stylelint-scss", "stylelint-order", "stylelint-prettier"], + overrides: [ + { + files: ["**/*.(css|html|vue)"], + customSyntax: "postcss-html" + }, + { + files: ["*.scss", "**/*.scss"], + customSyntax: "postcss-scss", + extends: [ + "stylelint-config-standard-scss", + "stylelint-config-recommended-vue/scss" + ] + } + ], + rules: { + "prettier/prettier": true, + "selector-class-pattern": null, + "no-descending-specificity": null, + "scss/dollar-variable-pattern": null, + "selector-pseudo-class-no-unknown": [ + true, + { + ignorePseudoClasses: ["deep", "global"] + } + ], + "selector-pseudo-element-no-unknown": [ + true, + { + ignorePseudoElements: ["v-deep", "v-global", "v-slotted"] + } + ], + "at-rule-no-unknown": [ + true, + { + ignoreAtRules: [ + "tailwind", + "apply", + "variants", + "responsive", + "screen", + "function", + "if", + "each", + "include", + "mixin", + "use" + ] + } + ], + "rule-empty-line-before": [ + "always", + { + ignore: ["after-comment", "first-nested"] + } + ], + "unit-no-unknown": [true, { ignoreUnits: ["rpx"] }], + "order/order": [ + [ + "dollar-variables", + "custom-properties", + "at-rules", + "declarations", + { + type: "at-rule", + name: "supports" + }, + { + type: "at-rule", + name: "media" + }, + "rules" + ], + { severity: "warning" } + ] + }, + ignoreFiles: ["**/*.js", "**/*.ts", "**/*.jsx", "**/*.tsx", "report.html"] +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..4cbdd39 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,55 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": false, + "strictFunctionTypes": false, + "noImplicitThis": true, + "jsx": "preserve", + "importHelpers": true, + "experimentalDecorators": true, + "skipLibCheck": true, + "esModuleInterop": true, + "isolatedModules": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "sourceMap": true, + "baseUrl": ".", + "allowJs": false, + "resolveJsonModule": true, + "lib": [ + "ESNext", + "DOM" + ], + "paths": { + "@/*": [ + "src/*" + ], + "@build/*": [ + "build/*" + ] + }, + "types": [ + "node", + "vite/client", + "element-plus/global", + "@pureadmin/table/volar", + "unplugin-icons/types/vue", + "@pureadmin/descriptions/volar" + ] + }, + "include": [ + "mock/*.ts", + "src/**/*.ts", + "src/**/*.tsx", + "src/**/*.vue", + "types/*.d.ts", + "vite.config.ts" + ], + "exclude": [ + "dist", + "**/*.js", + "node_modules" + ] +} \ No newline at end of file diff --git a/types/directives.d.ts b/types/directives.d.ts new file mode 100644 index 0000000..458fd09 --- /dev/null +++ b/types/directives.d.ts @@ -0,0 +1,28 @@ +import type { Directive } from "vue"; +import type { CopyEl, OptimizeOptions, RippleOptions } from "@/directives"; + +declare module "vue" { + export interface ComponentCustomProperties { + /** `Loading` 鍔ㄧ敾鍔犺浇鎸囦护锛屽叿浣撶湅锛歨ttps://element-plus.org/zh-CN/component/loading.html#%E6%8C%87%E4%BB%A4 */ + vLoading: Directive<Element, boolean>; + /** 鎸夐挳鏉冮檺鎸囦护锛堟牴鎹矾鐢盽meta`涓殑`auths`瀛楁杩涜鍒ゆ柇锛�*/ + vAuth: Directive<HTMLElement, string | Array<string>>; + /** 鏂囨湰澶嶅埗鎸囦护锛堥粯璁ゅ弻鍑诲鍒讹級 */ + vCopy: Directive<CopyEl, string>; + /** 闀挎寜鎸囦护 */ + vLongpress: Directive<HTMLElement, Function>; + /** 闃叉姈銆佽妭娴佹寚浠� */ + vOptimize: Directive<HTMLElement, OptimizeOptions>; + /** 鎸夐挳鏉冮檺鎸囦护锛堟牴鎹櫥褰曟帴鍙h繑鍥炵殑`permissions`瀛楁杩涜鍒ゆ柇锛�*/ + vPerms: Directive<HTMLElement, string | Array<string>>; + /** + * `v-ripple`鎸囦护锛岀敤娉曞涓嬶細 + * 1. `v-ripple`浠h〃鍚敤鍩烘湰鐨刞ripple`鍔熻兘 + * 2. `v-ripple="{ class: 'text-red' }"`浠h〃鑷畾涔塦ripple`棰滆壊锛屾敮鎸乣tailwindcss`锛岀敓鏁堟牱寮忔槸`color` + * 3. `v-ripple.center`浠h〃浠庝腑蹇冩墿鏁� + */ + vRipple: Directive<HTMLElement, RippleOptions>; + } +} + +export {}; diff --git a/types/global-components.d.ts b/types/global-components.d.ts new file mode 100644 index 0000000..238f62c --- /dev/null +++ b/types/global-components.d.ts @@ -0,0 +1,135 @@ +declare module "vue" { + /** + * 鑷畾涔夊叏灞�缁勪欢鑾峰緱 Volar 鎻愮ず锛堣嚜瀹氫箟鐨勫叏灞�缁勪欢闇�瑕佸湪杩欓噷澹版槑涓嬫墠鑳借幏寰� Volar 绫诲瀷鎻愮ず鍝︼級 + */ + export interface GlobalComponents { + IconifyIconOffline: (typeof import("../src/components/ReIcon"))["IconifyIconOffline"]; + IconifyIconOnline: (typeof import("../src/components/ReIcon"))["IconifyIconOnline"]; + FontIcon: (typeof import("../src/components/ReIcon"))["FontIcon"]; + Auth: (typeof import("../src/components/ReAuth"))["Auth"]; + Perms: (typeof import("../src/components/RePerms"))["Perms"]; + } +} + +/** + * TODO https://github.com/element-plus/element-plus/blob/dev/global.d.ts#L2 + * No need to install @vue/runtime-core + */ +declare module "vue" { + export interface GlobalComponents { + ElAffix: (typeof import("element-plus"))["ElAffix"]; + ElAlert: (typeof import("element-plus"))["ElAlert"]; + ElAside: (typeof import("element-plus"))["ElAside"]; + ElAutocomplete: (typeof import("element-plus"))["ElAutocomplete"]; + ElAvatar: (typeof import("element-plus"))["ElAvatar"]; + ElAnchor: (typeof import("element-plus"))["ElAnchor"]; + ElAnchorLink: (typeof import("element-plus"))["ElAnchorLink"]; + ElBacktop: (typeof import("element-plus"))["ElBacktop"]; + ElBadge: (typeof import("element-plus"))["ElBadge"]; + ElBreadcrumb: (typeof import("element-plus"))["ElBreadcrumb"]; + ElBreadcrumbItem: (typeof import("element-plus"))["ElBreadcrumbItem"]; + ElButton: (typeof import("element-plus"))["ElButton"]; + ElButtonGroup: (typeof import("element-plus"))["ElButtonGroup"]; + ElCalendar: (typeof import("element-plus"))["ElCalendar"]; + ElCard: (typeof import("element-plus"))["ElCard"]; + ElCarousel: (typeof import("element-plus"))["ElCarousel"]; + ElCarouselItem: (typeof import("element-plus"))["ElCarouselItem"]; + ElCascader: (typeof import("element-plus"))["ElCascader"]; + ElCascaderPanel: (typeof import("element-plus"))["ElCascaderPanel"]; + ElCheckbox: (typeof import("element-plus"))["ElCheckbox"]; + ElCheckboxButton: (typeof import("element-plus"))["ElCheckboxButton"]; + ElCheckboxGroup: (typeof import("element-plus"))["ElCheckboxGroup"]; + ElCol: (typeof import("element-plus"))["ElCol"]; + ElCollapse: (typeof import("element-plus"))["ElCollapse"]; + ElCollapseItem: (typeof import("element-plus"))["ElCollapseItem"]; + ElCollapseTransition: (typeof import("element-plus"))["ElCollapseTransition"]; + ElColorPicker: (typeof import("element-plus"))["ElColorPicker"]; + ElContainer: (typeof import("element-plus"))["ElContainer"]; + ElConfigProvider: (typeof import("element-plus"))["ElConfigProvider"]; + ElDatePicker: (typeof import("element-plus"))["ElDatePicker"]; + ElDialog: (typeof import("element-plus"))["ElDialog"]; + ElDivider: (typeof import("element-plus"))["ElDivider"]; + ElDrawer: (typeof import("element-plus"))["ElDrawer"]; + ElDropdown: (typeof import("element-plus"))["ElDropdown"]; + ElDropdownItem: (typeof import("element-plus"))["ElDropdownItem"]; + ElDropdownMenu: (typeof import("element-plus"))["ElDropdownMenu"]; + ElEmpty: (typeof import("element-plus"))["ElEmpty"]; + ElFooter: (typeof import("element-plus"))["ElFooter"]; + ElForm: (typeof import("element-plus"))["ElForm"]; + ElFormItem: (typeof import("element-plus"))["ElFormItem"]; + ElHeader: (typeof import("element-plus"))["ElHeader"]; + ElIcon: (typeof import("element-plus"))["ElIcon"]; + ElImage: (typeof import("element-plus"))["ElImage"]; + ElImageViewer: (typeof import("element-plus"))["ElImageViewer"]; + ElInput: (typeof import("element-plus"))["ElInput"]; + ElInputNumber: (typeof import("element-plus"))["ElInputNumber"]; + ElLink: (typeof import("element-plus"))["ElLink"]; + ElMain: (typeof import("element-plus"))["ElMain"]; + ElMenu: (typeof import("element-plus"))["ElMenu"]; + ElMenuItem: (typeof import("element-plus"))["ElMenuItem"]; + ElMenuItemGroup: (typeof import("element-plus"))["ElMenuItemGroup"]; + ElOption: (typeof import("element-plus"))["ElOption"]; + ElOptionGroup: (typeof import("element-plus"))["ElOptionGroup"]; + ElPageHeader: (typeof import("element-plus"))["ElPageHeader"]; + ElPagination: (typeof import("element-plus"))["ElPagination"]; + ElPopconfirm: (typeof import("element-plus"))["ElPopconfirm"]; + ElPopper: (typeof import("element-plus"))["ElPopper"]; + ElPopover: (typeof import("element-plus"))["ElPopover"]; + ElProgress: (typeof import("element-plus"))["ElProgress"]; + ElRadio: (typeof import("element-plus"))["ElRadio"]; + ElRadioButton: (typeof import("element-plus"))["ElRadioButton"]; + ElRadioGroup: (typeof import("element-plus"))["ElRadioGroup"]; + ElRate: (typeof import("element-plus"))["ElRate"]; + ElRow: (typeof import("element-plus"))["ElRow"]; + ElScrollbar: (typeof import("element-plus"))["ElScrollbar"]; + ElSelect: (typeof import("element-plus"))["ElSelect"]; + ElSlider: (typeof import("element-plus"))["ElSlider"]; + ElStep: (typeof import("element-plus"))["ElStep"]; + ElSteps: (typeof import("element-plus"))["ElSteps"]; + ElSubMenu: (typeof import("element-plus"))["ElSubMenu"]; + ElSwitch: (typeof import("element-plus"))["ElSwitch"]; + ElTabPane: (typeof import("element-plus"))["ElTabPane"]; + ElTable: (typeof import("element-plus"))["ElTable"]; + ElTableColumn: (typeof import("element-plus"))["ElTableColumn"]; + ElTabs: (typeof import("element-plus"))["ElTabs"]; + ElTag: (typeof import("element-plus"))["ElTag"]; + ElText: (typeof import("element-plus"))["ElText"]; + ElTimePicker: (typeof import("element-plus"))["ElTimePicker"]; + ElTimeSelect: (typeof import("element-plus"))["ElTimeSelect"]; + ElTimeline: (typeof import("element-plus"))["ElTimeline"]; + ElTimelineItem: (typeof import("element-plus"))["ElTimelineItem"]; + ElTooltip: (typeof import("element-plus"))["ElTooltip"]; + ElTransfer: (typeof import("element-plus"))["ElTransfer"]; + ElTree: (typeof import("element-plus"))["ElTree"]; + ElTreeV2: (typeof import("element-plus"))["ElTreeV2"]; + ElTreeSelect: (typeof import("element-plus"))["ElTreeSelect"]; + ElUpload: (typeof import("element-plus"))["ElUpload"]; + ElSpace: (typeof import("element-plus"))["ElSpace"]; + ElSkeleton: (typeof import("element-plus"))["ElSkeleton"]; + ElSkeletonItem: (typeof import("element-plus"))["ElSkeletonItem"]; + ElStatistic: (typeof import("element-plus"))["ElStatistic"]; + ElCheckTag: (typeof import("element-plus"))["ElCheckTag"]; + ElDescriptions: (typeof import("element-plus"))["ElDescriptions"]; + ElDescriptionsItem: (typeof import("element-plus"))["ElDescriptionsItem"]; + ElResult: (typeof import("element-plus"))["ElResult"]; + ElSelectV2: (typeof import("element-plus"))["ElSelectV2"]; + ElWatermark: (typeof import("element-plus"))["ElWatermark"]; + ElTour: (typeof import("element-plus"))["ElTour"]; + ElTourStep: (typeof import("element-plus"))["ElTourStep"]; + ElSegmented: (typeof import("element-plus"))["ElSegmented"]; + } + + interface ComponentCustomProperties { + $storage: ResponsiveStorage; + $message: (typeof import("element-plus"))["ElMessage"]; + $notify: (typeof import("element-plus"))["ElNotification"]; + $msgbox: (typeof import("element-plus"))["ElMessageBox"]; + $messageBox: (typeof import("element-plus"))["ElMessageBox"]; + $alert: (typeof import("element-plus"))["ElMessageBox"]["alert"]; + $confirm: (typeof import("element-plus"))["ElMessageBox"]["confirm"]; + $prompt: (typeof import("element-plus"))["ElMessageBox"]["prompt"]; + $loading: (typeof import("element-plus"))["ElLoadingService"]; + } +} + +export {}; diff --git a/types/global.d.ts b/types/global.d.ts new file mode 100644 index 0000000..d973250 --- /dev/null +++ b/types/global.d.ts @@ -0,0 +1,193 @@ +import type { ECharts } from "echarts"; +import type { TableColumns } from "@pureadmin/table"; + +/** + * 鍏ㄥ眬绫诲瀷澹版槑锛屾棤闇�寮曞叆鐩存帴鍦� `.vue` 銆乣.ts` 銆乣.tsx` 鏂囦欢浣跨敤鍗冲彲鑾峰緱绫诲瀷鎻愮ず + */ +declare global { + /** + * 骞冲彴鐨勫悕绉般�佺増鏈�佽繍琛屾墍闇�鐨刞node`鍜宍pnpm`鐗堟湰銆佷緷璧栥�佹渶鍚庢瀯寤烘椂闂寸殑绫诲瀷鎻愮ず + */ + const __APP_INFO__: { + pkg: { + name: string; + version: string; + engines: { + node: string; + pnpm: string; + }; + dependencies: Recordable<string>; + devDependencies: Recordable<string>; + }; + lastBuildTime: string; + }; + + /** + * Window 鐨勭被鍨嬫彁绀� + */ + interface Window { + // Global vue app instance + __APP__: App<Element>; + webkitCancelAnimationFrame: (handle: number) => void; + mozCancelAnimationFrame: (handle: number) => void; + oCancelAnimationFrame: (handle: number) => void; + msCancelAnimationFrame: (handle: number) => void; + webkitRequestAnimationFrame: (callback: FrameRequestCallback) => number; + mozRequestAnimationFrame: (callback: FrameRequestCallback) => number; + oRequestAnimationFrame: (callback: FrameRequestCallback) => number; + msRequestAnimationFrame: (callback: FrameRequestCallback) => number; + } + + /** + * Document 鐨勭被鍨嬫彁绀� + */ + interface Document { + webkitFullscreenElement?: Element; + mozFullScreenElement?: Element; + msFullscreenElement?: Element; + } + + /** + * 鎵撳寘鍘嬬缉鏍煎紡鐨勭被鍨嬪0鏄� + */ + type ViteCompression = + | "none" + | "gzip" + | "brotli" + | "both" + | "gzip-clear" + | "brotli-clear" + | "both-clear"; + + /** + * 鍏ㄥ眬鑷畾涔夌幆澧冨彉閲忕殑绫诲瀷澹版槑 + * @see {@link https://pure-admin.cn/pages/config/#%E5%85%B7%E4%BD%93%E9%85%8D%E7%BD%AE} + */ + interface ViteEnv { + VITE_PORT: number; + VITE_PUBLIC_PATH: string; + VITE_ROUTER_HISTORY: string; + VITE_CDN: boolean; + VITE_HIDE_HOME: string; + VITE_COMPRESSION: ViteCompression; + } + + /** + * 缁ф壙 `@pureadmin/table` 鐨� `TableColumns` 锛屾柟渚垮叏灞�鐩存帴璋冪敤 + */ + type TableColumnList = Array<TableColumns>; + + /** + * 瀵瑰簲 `public/platform-config.json` 鏂囦欢鐨勭被鍨嬪0鏄� + * @see {@link https://pure-admin.cn/pages/config/#platform-config-json} + */ + interface PlatformConfigs { + Version?: string; + Title?: string; + FixedHeader?: boolean; + HiddenSideBar?: boolean; + MultiTagsCache?: boolean; + MaxTagsLevel?: number; + KeepAlive?: boolean; + Locale?: string; + Layout?: string; + Theme?: string; + DarkMode?: boolean; + OverallStyle?: string; + Grey?: boolean; + Weak?: boolean; + HideTabs?: boolean; + HideFooter?: boolean; + Stretch?: boolean | number; + SidebarStatus?: boolean; + EpThemeColor?: string; + ShowLogo?: boolean; + ShowModel?: string; + MenuArrowIconNoTransition?: boolean; + CachingAsyncRoutes?: boolean; + TooltipEffect?: Effect; + ResponsiveStorageNameSpace?: string; + MenuSearchHistory?: number; + } + + /** + * 涓� `PlatformConfigs` 绫诲瀷涓嶅悓锛岃繖閲屾槸缂撳瓨鍒版祻瑙堝櫒鏈湴瀛樺偍鐨勭被鍨嬪0鏄� + * @see {@link https://pure-admin.cn/pages/config/#platform-config-json} + */ + interface StorageConfigs { + version?: string; + title?: string; + fixedHeader?: boolean; + hiddenSideBar?: boolean; + multiTagsCache?: boolean; + keepAlive?: boolean; + locale?: string; + layout?: string; + theme?: string; + darkMode?: boolean; + grey?: boolean; + weak?: boolean; + hideTabs?: boolean; + hideFooter?: boolean; + sidebarStatus?: boolean; + epThemeColor?: string; + themeColor?: string; + overallStyle?: string; + showLogo?: boolean; + showModel?: string; + menuSearchHistory?: number; + username?: string; + } + + /** + * `responsive-storage` 鏈湴鍝嶅簲寮� `storage` 鐨勭被鍨嬪0鏄� + */ + interface ResponsiveStorage { + locale: { + locale?: string; + }; + layout: { + layout?: string; + theme?: string; + darkMode?: boolean; + sidebarStatus?: boolean; + epThemeColor?: string; + themeColor?: string; + overallStyle?: string; + }; + configure: { + grey?: boolean; + weak?: boolean; + hideTabs?: boolean; + hideFooter?: boolean; + showLogo?: boolean; + showModel?: string; + multiTagsCache?: boolean; + stretch?: boolean | number; + }; + tags?: Array<any>; + } + + /** + * 骞冲彴閲屾墍鏈夌粍浠跺疄渚嬮兘鑳借闂埌鐨勫叏灞�灞炴�у璞$殑绫诲瀷澹版槑 + */ + interface GlobalPropertiesApi { + $echarts: ECharts; + $storage: ResponsiveStorage; + $config: PlatformConfigs; + } + + /** + * 鎵╁睍 `Element` + */ + interface Element { + // v-ripple 浣滅敤浜� src/directives/ripple/index.ts 鏂囦欢 + _ripple?: { + enabled?: boolean; + centered?: boolean; + class?: string; + circle?: boolean; + touched?: boolean; + }; + } +} diff --git a/types/index.d.ts b/types/index.d.ts new file mode 100644 index 0000000..404601a --- /dev/null +++ b/types/index.d.ts @@ -0,0 +1,80 @@ +// 姝ゆ枃浠惰窡鍚岀骇鐩綍鐨� global.d.ts 鏂囦欢涓�鏍蜂篃鏄叏灞�绫诲瀷澹版槑锛屽彧涓嶈繃杩欓噷瀛樻斁涓�浜涢浂鏁g殑鍏ㄥ眬绫诲瀷锛屾棤闇�寮曞叆鐩存帴鍦� .vue 銆�.ts 銆�.tsx 鏂囦欢浣跨敤鍗冲彲鑾峰緱绫诲瀷鎻愮ず + +type RefType<T> = T | null; + +type EmitType = (event: string, ...args: any[]) => void; + +type TargetContext = "_self" | "_blank"; + +type ComponentRef<T extends HTMLElement = HTMLDivElement> = + ComponentElRef<T> | null; + +type ElRef<T extends HTMLElement = HTMLDivElement> = Nullable<T>; + +type ForDataType<T> = { + [P in T]?: ForDataType<T[P]>; +}; + +type AnyFunction<T> = (...args: any[]) => T; + +type PropType<T> = VuePropType<T>; + +type Writable<T> = { + -readonly [P in keyof T]: T[P]; +}; + +type Nullable<T> = T | null; + +type NonNullable<T> = T extends null | undefined ? never : T; + +type Recordable<T = any> = Record<string, T>; + +type ReadonlyRecordable<T = any> = { + readonly [key: string]: T; +}; + +type Indexable<T = any> = { + [key: string]: T; +}; + +type DeepPartial<T> = { + [P in keyof T]?: DeepPartial<T[P]>; +}; + +type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never }; + +type Exclusive<T, U> = (Without<T, U> & U) | (Without<U, T> & T); + +type TimeoutHandle = ReturnType<typeof setTimeout>; + +type IntervalHandle = ReturnType<typeof setInterval>; + +type Effect = "light" | "dark"; + +interface ChangeEvent extends Event { + target: HTMLInputElement; +} + +interface WheelEvent { + path?: EventTarget[]; +} + +interface ImportMetaEnv extends ViteEnv { + __: unknown; +} + +interface Fn<T = any, R = T> { + (...arg: T[]): R; +} + +interface PromiseFn<T = any, R = T> { + (...arg: T[]): Promise<R>; +} + +interface ComponentElRef<T extends HTMLElement = HTMLDivElement> { + $el: T; +} + +function parseInt(s: string | number, radix?: number): number; + +function parseFloat(string: string | number): number; diff --git a/types/router.d.ts b/types/router.d.ts new file mode 100644 index 0000000..0355852 --- /dev/null +++ b/types/router.d.ts @@ -0,0 +1,109 @@ +// 鍏ㄥ眬璺敱绫诲瀷澹版槑 + +import type { RouteComponent, RouteLocationNormalized } from "vue-router"; +import type { FunctionalComponent } from "vue"; + +declare global { + interface ToRouteType extends RouteLocationNormalized { + meta: CustomizeRouteMeta; + } + + /** + * @description 瀹屾暣瀛愯矾鐢辩殑`meta`閰嶇疆琛� + */ + interface CustomizeRouteMeta { + /** 鑿滃崟鍚嶇О锛堝吋瀹瑰浗闄呭寲銆侀潪鍥介檯鍖栵紝濡備綍鐢ㄥ浗闄呭寲鐨勫啓娉曞氨蹇呴』鍦ㄦ牴鐩綍鐨刞locales`鏂囦欢澶逛笅瀵瑰簲娣诲姞锛� `蹇呭~` */ + title: string; + /** 鑿滃崟鍥炬爣 `鍙�塦 */ + icon?: string | FunctionalComponent; + /** 鑿滃崟鍚嶇О鍙充晶鐨勯澶栧浘鏍� */ + extraIcon?: string | FunctionalComponent; + /** 鏄惁鍦ㄨ彍鍗曚腑鏄剧ず锛堥粯璁true`锛塦鍙�塦 */ + showLink?: boolean; + /** 鏄惁鏄剧ず鐖剁骇鑿滃崟 `鍙�塦 */ + showParent?: boolean; + /** 椤甸潰绾у埆鏉冮檺璁剧疆 `鍙�塦 */ + roles?: Array<string>; + /** 鎸夐挳绾у埆鏉冮檺璁剧疆 `鍙�塦 */ + auths?: Array<string>; + /** 璺敱缁勪欢缂撳瓨锛堝紑鍚� `true`銆佸叧闂� `false`锛塦鍙�塦 */ + keepAlive?: boolean; + /** 鍐呭祵鐨刞iframe`閾炬帴 `鍙�塦 */ + frameSrc?: string; + /** `iframe`椤垫槸鍚﹀紑鍚娆″姞杞藉姩鐢伙紙榛樿`true`锛塦鍙�塦 */ + frameLoading?: boolean; + /** 椤甸潰鍔犺浇鍔ㄧ敾锛堜袱绉嶆ā寮忥紝绗簩绉嶆潈閲嶆洿楂橈紝绗竴绉嶇洿鎺ラ噰鐢╜vue`鍐呯疆鐨刞transitions`鍔ㄧ敾锛岀浜岀鏄娇鐢╜animate.css`缂栧啓杩涖�佺鍦哄姩鐢伙紝骞冲彴鏇存帹鑽愪娇鐢ㄧ浜岀妯″紡锛屽凡缁忓唴缃簡`animate.css`锛岀洿鎺ュ啓瀵瑰簲鐨勫姩鐢诲悕鍗冲彲锛塦鍙�塦 */ + transition?: { + /** + * @description 褰撳墠璺敱鍔ㄧ敾鏁堟灉 + * @see {@link https://next.router.vuejs.org/guide/advanced/transitions.html#transitions} + * @see animate.css {@link https://animate.style} + */ + name?: string; + /** 杩涘満鍔ㄧ敾 */ + enterTransition?: string; + /** 绂诲満鍔ㄧ敾 */ + leaveTransition?: string; + }; + /** 褰撳墠鑿滃崟鍚嶇О鎴栬嚜瀹氫箟淇℃伅绂佹娣诲姞鍒版爣绛鹃〉锛堥粯璁false`锛� */ + hiddenTag?: boolean; + /** 褰撳墠鑿滃崟鍚嶇О鏄惁鍥哄畾鏄剧ず鍦ㄦ爣绛鹃〉涓斾笉鍙叧闂紙榛樿`false`锛� */ + fixedTag?: boolean; + /** 鍔ㄦ�佽矾鐢卞彲鎵撳紑鐨勬渶澶ф暟閲� `鍙�塦 */ + dynamicLevel?: number; + /** 灏嗘煇涓彍鍗曟縺娲� + * 锛堜富瑕佺敤浜庨�氳繃`query`鎴朻params`浼犲弬鐨勮矾鐢憋紝褰撳畠浠�氳繃閰嶇疆`showLink: false`鍚庝笉鍦ㄨ彍鍗曚腑鏄剧ず锛屽氨涓嶄細鏈変换浣曡彍鍗曢珮浜紝 + * 鑰岄�氳繃璁剧疆`activePath`鎸囧畾婵�娲昏彍鍗曞嵆鍙幏寰楅珮浜紝`activePath`涓烘寚瀹氭縺娲昏彍鍗曠殑`path`锛� + */ + activePath?: string; + } + + /** + * @description 瀹屾暣瀛愯矾鐢遍厤缃〃 + */ + interface RouteChildrenConfigsTable { + /** 瀛愯矾鐢卞湴鍧� `蹇呭~` */ + path: string; + /** 璺敱鍚嶅瓧锛堝搴斾笉瑕侀噸澶嶏紝鍜屽綋鍓嶇粍浠剁殑`name`淇濇寔涓�鑷达級`蹇呭~` */ + name?: string; + /** 璺敱閲嶅畾鍚� `鍙�塦 */ + redirect?: string; + /** 鎸夐渶鍔犺浇缁勪欢 `鍙�塦 */ + component?: RouteComponent; + meta?: CustomizeRouteMeta; + /** 瀛愯矾鐢遍厤缃」 */ + children?: Array<RouteChildrenConfigsTable>; + } + + /** + * @description 鏁翠綋璺敱閰嶇疆琛紙鍖呮嫭瀹屾暣瀛愯矾鐢憋級 + */ + interface RouteConfigsTable { + /** 璺敱鍦板潃 `蹇呭~` */ + path: string; + /** 璺敱鍚嶅瓧锛堜繚鎸佸敮涓�锛塦鍙�塦 */ + name?: string; + /** `Layout`缁勪欢 `鍙�塦 */ + component?: RouteComponent; + /** 璺敱閲嶅畾鍚� `鍙�塦 */ + redirect?: string; + meta?: { + /** 鑿滃崟鍚嶇О锛堝吋瀹瑰浗闄呭寲銆侀潪鍥介檯鍖栵紝濡備綍鐢ㄥ浗闄呭寲鐨勫啓娉曞氨蹇呴』鍦ㄦ牴鐩綍鐨刞locales`鏂囦欢澶逛笅瀵瑰簲娣诲姞锛塦蹇呭~` */ + title: string; + /** 鑿滃崟鍥炬爣 `鍙�塦 */ + icon?: string | FunctionalComponent; + /** 鏄惁鍦ㄨ彍鍗曚腑鏄剧ず锛堥粯璁true`锛塦鍙�塦 */ + showLink?: boolean; + /** 鑿滃崟鍗囧簭鎺掑簭锛屽�艰秺楂樻帓鐨勮秺鍚庯紙鍙拡瀵归《绾ц矾鐢憋級`鍙�塦 */ + rank?: number; + }; + /** 瀛愯矾鐢遍厤缃」 */ + children?: Array<RouteChildrenConfigsTable>; + } +} + +// https://router.vuejs.org/zh/guide/advanced/meta.html#typescript +declare module "vue-router" { + // eslint-disable-next-line + interface RouteMeta extends CustomizeRouteMeta {} +} diff --git a/types/shims-tsx.d.ts b/types/shims-tsx.d.ts new file mode 100644 index 0000000..fb9ce97 --- /dev/null +++ b/types/shims-tsx.d.ts @@ -0,0 +1,24 @@ +import type Vue, { type VNode } from "vue"; + +declare module "*.tsx" { + import Vue from "compatible-vue"; + export default Vue; +} + +declare global { + namespace JSX { + // eslint-disable-next-line + interface Element extends VNode {} + // eslint-disable-next-line + interface ElementClass extends Vue {} + interface ElementAttributesProperty { + $props: any; + } + interface IntrinsicElements { + [elem: string]: any; + } + interface IntrinsicAttributes { + [elem: string]: any; + } + } +} diff --git a/types/shims-vue.d.ts b/types/shims-vue.d.ts new file mode 100644 index 0000000..0d16394 --- /dev/null +++ b/types/shims-vue.d.ts @@ -0,0 +1,11 @@ +declare module "*.vue" { + import type { DefineComponent } from "vue"; + // eslint-disable-next-line + const component: DefineComponent<{}, {}, any>; + export default component; +} + +declare module "*.scss" { + const scss: Record<string, string>; + export default scss; +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..1d1b01a --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,62 @@ +import { getPluginsList } from "./build/plugins"; +import { include, exclude } from "./build/optimize"; +import { type UserConfigExport, type ConfigEnv, loadEnv } from "vite"; +import { + root, + alias, + wrapperEnv, + pathResolve, + __APP_INFO__ +} from "./build/utils"; + +export default ({ mode }: ConfigEnv): UserConfigExport => { + const { VITE_CDN, VITE_PORT, VITE_COMPRESSION, VITE_PUBLIC_PATH } = + wrapperEnv(loadEnv(mode, root)); + return { + base: VITE_PUBLIC_PATH, + root, + resolve: { + alias + }, + // 鏈嶅姟绔覆鏌� + server: { + // 绔彛鍙� + port: VITE_PORT, + host: "0.0.0.0", + // 鏈湴璺ㄥ煙浠g悊 https://cn.vitejs.dev/config/server-options.html#server-proxy + proxy: {}, + // 棰勭儹鏂囦欢浠ユ彁鍓嶈浆鎹㈠拰缂撳瓨缁撴灉锛岄檷浣庡惎鍔ㄦ湡闂寸殑鍒濆椤甸潰鍔犺浇鏃堕暱骞堕槻姝㈣浆鎹㈢�戝竷 + warmup: { + clientFiles: ["./index.html", "./src/{views,components}/*"] + } + }, + plugins: getPluginsList(VITE_CDN, VITE_COMPRESSION), + // https://cn.vitejs.dev/config/dep-optimization-options.html#dep-optimization-options + optimizeDeps: { + include, + exclude + }, + build: { + // https://cn.vitejs.dev/guide/build.html#browser-compatibility + target: "es2015", + sourcemap: false, + // 娑堥櫎鎵撳寘澶у皬瓒呰繃500kb璀﹀憡 + chunkSizeWarningLimit: 4000, + rollupOptions: { + input: { + index: pathResolve("./index.html", import.meta.url) + }, + // 闈欐�佽祫婧愬垎绫绘墦鍖� + output: { + chunkFileNames: "static/js/[name]-[hash].js", + entryFileNames: "static/js/[name]-[hash].js", + assetFileNames: "static/[ext]/[name]-[hash].[ext]" + } + } + }, + define: { + __INTLIFY_PROD_DEVTOOLS__: false, + __APP_INFO__: JSON.stringify(__APP_INFO__) + } + }; +}; -- Gitblit v1.9.1