[
  {
    "path": ".editorconfig",
    "content": ""
  },
  {
    "path": ".eslintignore",
    "content": "public\nnode_modules\n.history\n.husky\ndist\n*.d.ts\n"
  },
  {
    "path": ".eslintrc.json",
    "content": "{\n  \"root\": true,\n  \"extends\": [\"./eslintrc/eslint-config.cjs\", \"./eslintrc/.eslintrc-auto-import.json\"]\n}\n"
  },
  {
    "path": ".gitignore",
    "content": "# compiled output\n/dist\n/dist-ssr\n/node_modules\n\n#lock\npnpm-lock.yaml\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# OS\n.DS_Store\n\n# Tests\n/coverage\n/.nyc_output\n\n# IDEs and editors\n/.idea\n.project\n.classpath\n.c9/\n*.launch\n.settings/\n*.sublime-workspace\n\n# IDE - VSCode\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n\n# Other\n.history\n*.local\nyarn*\npnpm*\n\n\n#.eslintrc-auto-import.json\n#auto-imports.d.ts\n#components.d.ts\nstats.html\n"
  },
  {
    "path": ".husky/commit-msg",
    "content": "#!/bin/sh\r\n#. \"$(dirname \"$0\")/_/husky.sh\"\r\n#在项目中我们会使用commit-msg这个git hook来校验我们commit时添加的备注信息是否符合规范。在以前的我们通常是这样配置：\r\n#--no-install 参数表示强制npx使用项目中node_modules目录中的commitlint包(如果需要开启，注意：需要安装npx)\r\n#npx --no-install commitlint --edit $1\r\n"
  },
  {
    "path": ".husky/pre-commit",
    "content": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\n#推送之前运行eslint检查\nnpm  run lint\n#推送之前运行单元测试检查\n#npm run test:unit\n\n"
  },
  {
    "path": ".npmrc",
    "content": "shamefully-hoist=true\nstrict-peer-dependencies=false\n\n###aliyun address\nregistry = https://registry.npmmirror.com\n\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\r\n    \"useTabs\": false,\r\n    \"tabWidth\": 2,\r\n    \"printWidth\": 120,\r\n    \"singleQuote\": true,\r\n    \"trailingComma\": \"none\",\r\n    \"bracketSpacing\": true,\r\n    \"semi\": false,\r\n    \"htmlWhitespaceSensitivity\": \"ignore\"\r\n}\r\n"
  },
  {
    "path": ".vscode/extensions.json",
    "content": "{\n  \"recommendations\": [\"johnsoncodehk.volar\", \"esbenp.prettier-vscode\",\"dbaeumer.vscode-eslint\"]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"editor.defaultFormatter\": \"esbenp.prettier-vscode\",\n  \"npm.packageManager\": \"yarn\"\n}\n"
  },
  {
    "path": "README.md",
    "content": "# vue3-admin-ts\n\nthe typescript version of  vue3 admin template \n \nsuggestion the Node.js >= v16.20\n\n[Recommended node](https://nodejs.org/download/release/v16.20.2/)\n\n\n## Documents\n\n- [Official Documentation](https://github.jzfai.top/vue3-admin-doc/)\n\n- [中文官网](https://github.jzfai.top/vue3-admin-cn-doc/)\n\n\n\n## Online experience\n\n[Access address](https://github.jzfai.top/vue3-admin-ts)\n\n[国内体验地址](https://github.jzfai.top/vue3-admin-ts)\n\n\n\n## Related items\n\nThe framework is available in js,ts, plus and electron versions\n- js version：[vue3-admin-template](https://github.com/jzfai/vue3-admin-template.git) -- basic version\n- ts version：[vue3-element-ts](https://github.com/jzfai/vue3-admin-ts.git)\n- ts version for plus：[vue3-element-plus](https://github.com/jzfai/vue3-admin-plus.git)\n- ts version for electron：[vue3-element-electron](https://github.com/jzfai/vue3-admin-electron.git)\n- java Micro-service background data：[micro-service-plus](https://github.com/jzfai/micro-service-plus)\n\n\n## Build Setup\n\n```bash\n# clone the project\ngit clone https://github.com/jzfai/vue3-admin-ts.git\n\n# enter the project directory\ncd vue3-admin-ts\n\n# pnpm address https://pnpm.io/zh/motivation\n# install dependency(Recommend use pnpm)\n# you can  use \"npm -g i pnpm@7.9.0\" to install pnpm \npnpm i\n\n# develop\npnpm run dev\n```\n\n\n## Build\n\n```bash\n# build for test environment\npnpm run build-test\n\n# build for production environment\npnpm run  build\n```\n\n## Others\n\n```bash\n# preview the release environment effect\npnpm run preview\n\n# code format check\npnpm run lint\n\n```\n\n\n## Browsers support\n\nNote: Vue3 is not supported the Internet Explorer\n\n\n## Discussion and Communication\n[WeChat group](https://github.jzfai.top/file/images/wx-groud.png)\n\n\n\n"
  },
  {
    "path": "eslintrc/.eslintrc-auto-import.json",
    "content": "{\n  \"globals\": {\n    \"EffectScope\": true,\n    \"axiosReq\": true,\n    \"bus\": true,\n    \"buttonCodes\": true,\n    \"casHandleChange\": true,\n    \"cloneDeep\": true,\n    \"closeElLoading\": true,\n    \"codesPermission\": true,\n    \"commonUtil\": true,\n    \"computed\": true,\n    \"copyValueToClipboard\": true,\n    \"createApp\": true,\n    \"customRef\": true,\n    \"defineAsyncComponent\": true,\n    \"defineComponent\": true,\n    \"directives\": true,\n    \"effectScope\": true,\n    \"elConfirm\": true,\n    \"elConfirmNoCancelBtn\": true,\n    \"elLoading\": true,\n    \"elMessage\": true,\n    \"elNotify\": true,\n    \"filterAsyncRouter\": true,\n    \"filterAsyncRouterByCodes\": true,\n    \"filterAsyncRoutesByMenuList\": true,\n    \"filterAsyncRoutesByRoles\": true,\n    \"freshRouter\": true,\n    \"getCurrentInstance\": true,\n    \"getCurrentScope\": true,\n    \"getLangInstance\": true,\n    \"getQueryParam\": true,\n    \"h\": true,\n    \"inject\": true,\n    \"isExternal\": true,\n    \"isProxy\": true,\n    \"isReactive\": true,\n    \"isReadonly\": true,\n    \"isRef\": true,\n    \"lang\": true,\n    \"langTitle\": true,\n    \"markRaw\": true,\n    \"nextTick\": true,\n    \"onActivated\": true,\n    \"onBeforeMount\": true,\n    \"onBeforeRouteLeave\": true,\n    \"onBeforeRouteUpdate\": true,\n    \"onBeforeUnmount\": true,\n    \"onBeforeUpdate\": true,\n    \"onDeactivated\": true,\n    \"onErrorCaptured\": true,\n    \"onMounted\": true,\n    \"onRenderTracked\": true,\n    \"onRenderTriggered\": true,\n    \"onScopeDispose\": true,\n    \"onServerPrefetch\": true,\n    \"onUnmounted\": true,\n    \"onUpdated\": true,\n    \"progressClose\": true,\n    \"progressStart\": true,\n    \"provide\": true,\n    \"reactive\": true,\n    \"readonly\": true,\n    \"ref\": true,\n    \"resetRouter\": true,\n    \"resetState\": true,\n    \"resizeHandler\": true,\n    \"resolveComponent\": true,\n    \"resolveDirective\": true,\n    \"rolesPermission\": true,\n    \"routeInfo\": true,\n    \"routerBack\": true,\n    \"routerPush\": true,\n    \"routerReplace\": true,\n    \"shallowReactive\": true,\n    \"shallowReadonly\": true,\n    \"shallowRef\": true,\n    \"sleepTimeout\": true,\n    \"storeToRefs\": true,\n    \"toRaw\": true,\n    \"toRef\": true,\n    \"toRefs\": true,\n    \"triggerRef\": true,\n    \"unref\": true,\n    \"useAttrs\": true,\n    \"useBasicStore\": true,\n    \"useConfigStore\": true,\n    \"useCssModule\": true,\n    \"useCssVars\": true,\n    \"useElement\": true,\n    \"useErrorLog\": true,\n    \"useLink\": true,\n    \"useRoute\": true,\n    \"useRouter\": true,\n    \"useSlots\": true,\n    \"useTable\": true,\n    \"useTagsViewStore\": true,\n    \"watch\": true,\n    \"watchEffect\": true,\n    \"watchPostEffect\": true,\n    \"watchSyncEffect\": true\n  }\n}"
  },
  {
    "path": "eslintrc/eslint-config.cjs",
    "content": "// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst { defineConfig } = require('eslint-define-config')\nmodule.exports = defineConfig({\n  env: {\n    es6: true,\n    browser: true,\n    node: true\n  },\n  plugins: ['@typescript-eslint', 'prettier', 'unicorn'],\n  extends: [\n    'eslint:recommended',\n    'plugin:import/recommended',\n    'plugin:eslint-comments/recommended',\n    'plugin:jsonc/recommended-with-jsonc',\n    'plugin:markdown/recommended',\n    'plugin:vue/vue3-recommended',\n    'plugin:@typescript-eslint/recommended',\n    'prettier'\n  ],\n  settings: {\n    'import/resolver': {\n      node: { extensions: ['.js', '.mjs', '.ts', '.d.ts', '.tsx'] }\n    }\n  },\n  overrides: [\n    {\n      files: ['*.ts', '*.vue'],\n      rules: {\n        'no-undef': 'off',\n        '@typescript-eslint/ban-types': 'off'\n      }\n    },\n    {\n      files: ['*.js'],\n      rules: {\n        '@typescript-eslint/no-var-requires': 'off'\n      }\n    },\n    {\n      files: ['*.vue'],\n      parser: 'vue-eslint-parser',\n      parserOptions: {\n        parser: '@typescript-eslint/parser',\n        extraFileExtensions: ['.vue'],\n        ecmaVersion: 'latest',\n        ecmaFeatures: {\n          jsx: true\n        }\n      },\n      rules: {\n        'no-undef': 'off',\n        '@typescript-eslint/no-unused-vars': 'off',\n        '@typescript-eslint/no-empty-function': 'off'\n      }\n    }\n  ],\n  rules: {\n    // js/ts\n    camelcase: ['error', { properties: 'never' }],\n    'no-console': ['warn', { allow: ['error'] }],\n    'no-debugger': 'warn',\n    'no-constant-condition': ['error', { checkLoops: false }],\n    'no-restricted-syntax': ['error', 'LabeledStatement', 'WithStatement'],\n    'no-return-await': 'error',\n    'no-var': 'error',\n    'no-empty': ['error', { allowEmptyCatch: true }],\n    'prefer-const': ['warn', { destructuring: 'all', ignoreReadBeforeAssign: true }],\n    'prefer-arrow-callback': ['error', { allowNamedFunctions: false, allowUnboundThis: true }],\n    'object-shorthand': ['error', 'always', { ignoreConstructors: false, avoidQuotes: true }],\n    'prefer-rest-params': 'error',\n    'prefer-spread': 'error',\n    'prefer-template': 'error',\n    'no-redeclare': 'off',\n    '@typescript-eslint/no-redeclare': 'error',\n    // best-practice\n    'array-callback-return': 'error',\n    'block-scoped-var': 'error',\n    'no-alert': 'warn',\n    'no-case-declarations': 'error',\n    'no-multi-str': 'error',\n    'no-with': 'error',\n    'no-void': 'error',\n    'sort-imports': [\n      'warn',\n      {\n        ignoreCase: false,\n        ignoreDeclarationSort: true,\n        ignoreMemberSort: false,\n        memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'],\n        allowSeparatedGroups: false\n      }\n    ],\n    // stylistic-issues\n    'prefer-exponentiation-operator': 'error',\n\n    // ts\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n    '@typescript-eslint/no-non-null-assertion': 'off',\n    '@typescript-eslint/no-non-null-asserted-optional-chain': 'off',\n    '@typescript-eslint/consistent-type-imports': ['error', { disallowTypeAnnotations: false }],\n    '@typescript-eslint/ban-ts-comment': ['off', { 'ts-ignore': false }],\n    '@typescript-eslint/no-empty-function': 'off',\n    // vue\n    'vue/no-v-html': 'off',\n    'vue/require-default-prop': 'off',\n    'vue/require-explicit-emits': 'off',\n    'vue/multi-word-component-names': 'off',\n    'vue/prefer-import-from-vue': 'off',\n    'vue/no-v-text-v-html-on-component': 'off',\n    'vue/html-self-closing': [\n      'error',\n      {\n        html: {\n          void: 'always',\n          normal: 'always',\n          component: 'always'\n        },\n        svg: 'always',\n        math: 'always'\n      }\n    ],\n\n    // prettier\n    //fix lf error\n    'prettier/prettier': 'off',\n    // import\n    'import/first': 'warn',\n    'import/no-duplicates': 'error',\n    'import/order': [\n      'error',\n      {\n        groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],\n\n        pathGroups: [\n          {\n            pattern: 'vue',\n            group: 'external',\n            position: 'before'\n          }\n        ],\n        pathGroupsExcludedImportTypes: ['type']\n      }\n    ],\n    'import/no-unresolved': 'off',\n    'import/namespace': 'off',\n    'import/default': 'off',\n    'import/no-named-as-default': 'off',\n    'import/no-named-as-default-member': 'off',\n    'import/named': 'off',\n\n    // eslint-plugin-eslint-comments\n    'eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }],\n\n    // unicorn\n    'unicorn/custom-error-definition': 'error',\n    'unicorn/error-message': 'error',\n    'unicorn/escape-case': 'error',\n    'unicorn/import-index': 'error',\n    'unicorn/new-for-builtins': 'error',\n    'unicorn/no-array-method-this-argument': 'error',\n    'unicorn/no-array-push-push': 'error',\n    'unicorn/no-console-spaces': 'error',\n    'unicorn/no-for-loop': 'error',\n    'unicorn/no-hex-escape': 'error',\n    'unicorn/no-instanceof-array': 'error',\n    'unicorn/no-invalid-remove-event-listener': 'error',\n    'unicorn/no-new-array': 'error',\n    'unicorn/no-new-buffer': 'error',\n    'unicorn/no-unsafe-regex': 'off',\n    'unicorn/number-literal-case': 'error',\n    'unicorn/prefer-array-find': 'error',\n    'unicorn/prefer-array-flat-map': 'error',\n    'unicorn/prefer-array-index-of': 'error',\n    'unicorn/prefer-array-some': 'error',\n    'unicorn/prefer-date-now': 'error',\n    'unicorn/prefer-dom-node-dataset': 'error',\n    'unicorn/prefer-includes': 'error',\n    'unicorn/prefer-keyboard-event-key': 'error',\n    'unicorn/prefer-math-trunc': 'error',\n    'unicorn/prefer-modern-dom-apis': 'error',\n    'unicorn/prefer-negative-index': 'error',\n    'unicorn/prefer-number-properties': 'error',\n    'unicorn/prefer-optional-catch-binding': 'error',\n    'unicorn/prefer-prototype-methods': 'error',\n    'unicorn/prefer-query-selector': 'error',\n    'unicorn/prefer-reflect-apply': 'error',\n    'unicorn/prefer-string-slice': 'error',\n    'unicorn/prefer-string-starts-ends-with': 'error',\n    'unicorn/prefer-string-trim-start-end': 'error',\n    'unicorn/prefer-type-error': 'error',\n    'unicorn/throw-new-error': 'error'\n  }\n})\n"
  },
  {
    "path": "index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" class=\"base-theme\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" href=\"/favicon.ico\" />\n    <link rel=\"stylesheet\" href=\"src/styles/init-loading.css\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title><%= title %></title>\n  </head>\n  <body>\n    <div id=\"app\">\n<!--      <div class=\"loader-wrapper\">-->\n<!--        <img src=\"src/assets/gif/dianchi.gif\"  class=\"loading-gif\">-->\n<!--        <div class=\"load_title\">正在加载系统资源，请耐心等待</div>-->\n<!--      </div>-->\n    </div>\n    <script type=\"module\" src=\"/src/main.ts\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "mock/example.ts",
    "content": "export default [\n  {\n    url: '/getMapInfo',\n    method: 'get',\n    response: () => {\n      return {\n        code: 200,\n        title: 'mock请求测试'\n      }\n    }\n  }\n]\n"
  },
  {
    "path": "mock/user.ts",
    "content": "const user = {\n  url: '/mock/login',\n  method: 'post',\n  response: () => {\n    return {\n      code: 20000,\n      jwtToken:\"666666\"\n    }\n  }\n}\n\nconst loginOut = {\n  url: '/mock/loginOut',\n  method: 'post',\n  response: () => {\n    return {\n      code: 200,\n      title: 'mock请求测试'\n    }\n  }\n}\n\nexport default [\n  user,loginOut\n]\n"
  },
  {
    "path": "optimize-include.ts",
    "content": "// const fs = require('fs')\n// const files = fs.readdirSync(\n//   'D:\\\\github\\\\vue3-admin-ts\\\\node_modules\\\\.pnpm\\\\element-plus@2.2.9_vue@3.2.37\\\\node_modules\\\\element-plus\\\\es\\\\components\\\\'\n// )\n// console.log(111, JSON.stringify(files))\n// console.log(console.dir(files))\n// console.log(console.dir(files.slice(20)))\n\nimport { resolve } from 'path'\n\nconst elementPlusComponentNameArr = [\n  'affix',\n  'alert',\n  'aside',\n  'autocomplete',\n  'avatar',\n  'backtop',\n  'badge',\n  'base',\n  'breadcrumb',\n  'breadcrumb-item',\n  'button',\n  'button-group',\n  'calendar',\n  'card',\n  'carousel',\n  'carousel-item',\n  'cascader',\n  'cascader-panel',\n  'check-tag',\n  'checkbox',\n  'checkbox-button',\n  'checkbox-group',\n  'col',\n  'collapse',\n  'collapse-item',\n  'collapse-transition',\n  'color-picker',\n  'config-provider',\n  'container',\n  'date-picker',\n  'descriptions',\n  'descriptions-item',\n  'dialog',\n  'divider',\n  'drawer',\n  'dropdown',\n  'dropdown-item',\n  'dropdown-menu',\n  'empty',\n  'footer',\n  'form',\n  'form-item',\n  'header',\n  'icon',\n  'image',\n  'image-viewer',\n  'infinite-scroll',\n  'input',\n  'input-number',\n  'link',\n  'loading',\n  'main',\n  'menu',\n  'menu-item',\n  'menu-item-group',\n  'message',\n  'message-box',\n  'notification',\n  'option',\n  'option-group',\n  'overlay',\n  'page-header',\n  'pagination',\n  'popconfirm',\n  'popover',\n  'popper',\n  'progress',\n  'radio',\n  'radio-button',\n  'radio-group',\n  'rate',\n  'result',\n  'row',\n  'scrollbar',\n  'select',\n  'select-v2',\n  'skeleton',\n  'skeleton-item',\n  'slider',\n  'space',\n  'step',\n  'steps',\n  'sub-menu',\n  'switch',\n  'tab-pane',\n  'table',\n  'table-column',\n  'table-v2',\n  'tabs',\n  'tag',\n  'teleport',\n  'time-picker',\n  'time-select',\n  'timeline',\n  'timeline-item',\n  'tooltip',\n  'transfer',\n  'tree',\n  'tree-select',\n  'tree-v2',\n  'upload',\n  'virtual-list'\n]\n\nexport const pkgPath = resolve(__dirname, './package.json')\n\n// eslint-disable-next-line @typescript-eslint/no-var-requires\nlet { dependencies } = require(pkgPath)\ndependencies = Object.keys(dependencies).filter((dep) => !dep.startsWith('@types/'))\n\nconst EPDepsArr = () => {\n  const depsArr = [] as string[]\n  elementPlusComponentNameArr.forEach((feItem) => {\n    depsArr.push(`element-plus/es/components/${feItem}/style/index`)\n  })\n  return depsArr\n}\n\nexport const optimizeElementPlus = EPDepsArr()\nexport const optimizeDependencies = dependencies\n\nexport default []\n"
  },
  {
    "path": "package.json",
    "content": "{\n    \"name\": \"vue3-admin-ts\",\n    \"version\": \"2.2.0\",\n    \"license\": \"MIT\",\n    \"author\": \"kuanghua(869653722@qq.com)\",\n    \"packageManager\": \"pnpm@7.9.0\",\n    \"type\": \"module\",\n    \"scripts\": {\n        \"dev\": \"vite --mode serve-dev\",\n        \"local\": \"vite --mode serve-local\",\n        \"debug\": \"vite --mode serve-dev --debug\",\n        \"test\": \"vite --mode serve-test\",\n        \"build:test\": \"vite build --mode  build-test\",\n        \"build\": \"vite build --mode build\",\n        \"preview:build\": \"npm run build && vite preview \",\n        \"preview\": \"vite preview \",\n        \"lint\": \"eslint --ext .js,.jsx,.vue,.ts,.tsx src --fix\",\n        \"prepare\": \"husky install\",\n        \"tsc-check\": \"tsc\",\n        \"vitest\": \"vitest --ui\",\n        \"coverage\": \"vitest run --coverage\"\n    },\n    \"peerDependencies\": {\n        \"vue\": \"^3.4.14\"\n    },\n    \"dependencies\": {\n        \"@element-plus/icons-vue\": \"^2.0.4\",\n        \"axios\": \"1.6.5\",\n        \"codemirror\": \"^6.0.1\",\n        \"echarts\": \"5.3.2\",\n        \"element-plus\": \"2.5.3\",\n        \"js-error-collection\": \"^1.0.7\",\n        \"json-editor-vue3\": \"^1.0.8\",\n        \"mitt\": \"3.0.0\",\n        \"moment-mini\": \"2.22.1\",\n        \"nprogress\": \"0.2.0\",\n        \"path\": \"0.12.7\",\n        \"path-browserify\": \"^1.0.1\",\n        \"path-to-regexp\": \"^6.2.1\",\n        \"pinia\": \"^2.0.16\",\n        \"pinia-plugin-persistedstate\": \"2.3.0\",\n        \"screenfull\": \"^6.0.2\",\n        \"sortablejs\": \"^1.15.0\",\n        \"vue\": \"^3.4.14\",\n        \"vue-clipboard3\": \"^2.0.0\",\n        \"vue-codemirror\": \"^6.1.1\",\n        \"vue-i18n\": \"9.1.10\",\n        \"vue-router\": \"^4.1.5\",\n        \"@codemirror/lang-javascript\": \"^6.1.0\",\n        \"@codemirror/theme-one-dark\": \"^6.1.0\"\n    },\n    \"devDependencies\": {\n        \"@babel/eslint-parser\": \"7.16.3\",\n        \"@originjs/vite-plugin-commonjs\": \"^1.0.3\",\n        \"@types/mockjs\": \"1.0.10\",\n        \"@types/node\": \"^17.0.35\",\n        \"@types/path-browserify\": \"^1.0.0\",\n        \"@types/sortablejs\": \"^1.15.0\",\n        \"@typescript-eslint/eslint-plugin\": \"5.30.0\",\n        \"@typescript-eslint/parser\": \"5.30.0\",\n        \"@vitejs/plugin-legacy\": \"^5.2.0\",\n        \"@vitejs/plugin-vue\": \"^5.0.3\",\n        \"@vitejs/plugin-vue-jsx\": \"^3.1.0\",\n        \"@vitest/coverage-c8\": \"^0.33.0\",\n        \"@vitest/ui\": \"^1.2.0\",\n        \"@vue/cli-plugin-unit-jest\": \"4.5.17\",\n        \"@vue/cli-service\": \"5.0.8\",\n        \"@vue/test-utils\": \"^2.0.2\",\n        \"@vueuse/core\": \"^8.7.5\",\n        \"eslint\": \"8.18.0\",\n        \"eslint-config-prettier\": \"8.5.0\",\n        \"eslint-define-config\": \"1.5.1\",\n        \"eslint-plugin-eslint-comments\": \"3.2.0\",\n        \"eslint-plugin-import\": \"2.26.0\",\n        \"eslint-plugin-jsonc\": \"^2.3.0\",\n        \"eslint-plugin-markdown\": \"^3.0.0\",\n        \"eslint-plugin-prettier\": \"4.1.0\",\n        \"eslint-plugin-simple-import-sort\": \"^10.0.0\",\n        \"eslint-plugin-unicorn\": \"^43.0.2\",\n        \"eslint-plugin-vue\": \"9.1.1\",\n        \"husky\": \"7.0.2\",\n        \"jsdom\": \"16.4.0\",\n        \"jsonc-eslint-parser\": \"^2.1.0\",\n        \"majestic\": \"1.8.1\",\n        \"mockjs\": \"1.1.0\",\n        \"prettier\": \"2.2.1\",\n        \"resize-observer-polyfill\": \"^1.5.1\",\n        \"rollup-plugin-visualizer\": \"^5.8.3\",\n        \"sass\": \"1.77.6\",\n        \"svg-sprite-loader\": \"6.0.11\",\n        \"typescript\": \"^4.7.2\",\n        \"unocss\": \"^0.58.3\",\n        \"unplugin-auto-import\": \"^0.11.2\",\n        \"unplugin-vue-components\": \"^0.22.8\",\n\n        \"unplugin-vue-define-options\": \"^0.6.1\",\n        \"vite\": \"^5.0.11\",\n        \"vite-plugin-html\": \"^3.2.0\",\n        \"vite-plugin-mkcert\": \"^1.7.2\",\n        \"vite-plugin-mock\": \"^3.0.1\",\n        \"vite-plugin-style-import\": \"1.2.1\",\n        \"vite-plugin-svg-icons\": \"^2.0.1\",\n        \"vitest\": \"^0.22.1\",\n        \"vue-tsc\": \"^0.34.16\"\n    },\n    \"pnpm\": {\n        \"peerDependencyRules\": {\n            \"ignoreMissing\": [\n                \"html-webpack-plugin\",\n                \"vite-plugin-mock\",\n                \"unplugin-auto-import\",\n                \"unplugin-vue-components\",\n                \"vue-template-compiler\",\n                \"unocss\",\n                \"unplugin\",\n                \"vite-plugin-mock\",\n                \"@vitejs/plugin-legacy\",\n                \"@vitejs/plugin-vue\",\n                \"@vitejs/*\",\n                \"@babel/*\",\n                \"vite\",\n                \"vue\",\n                \"@unocss/vite\",\n                \"rollup\",\n                \"vue-jest\",\n                \"@babel/*\"\n            ]\n        }\n    },\n    \"browserslist\": [\n        \"> 1%\",\n        \"not ie 11\",\n        \"not op_mini all\"\n    ],\n    \"engines\": {\n        \"node\": \">= 16 <20\",\n        \"pnpm\": \">= 6 <9\"\n    }\n}\n"
  },
  {
    "path": "src/App.vue",
    "content": "<template>\n  <el-config-provider :locale=\"lang[language]\" namespace=\"el\" :size=\"size\">\n    <router-view />\n  </el-config-provider>\n</template>\n<script setup lang=\"ts\">\nimport { onBeforeMount, onMounted } from 'vue'\n//element-plus lang\nimport zh from 'element-plus/dist/locale/zh-cn.mjs'\nimport en from 'element-plus/dist/locale/en.mjs'\nimport { storeToRefs } from 'pinia/dist/pinia'\nimport { useRoute } from 'vue-router'\nimport { useBasicStore } from '@/store/basic'\nimport { useConfigStore } from '@/store/config'\nimport { useErrorLog } from '@/hooks/use-error-log'\n\n//reshow default setting\nimport { toggleHtmlClass } from '@/theme/utils'\nconst lang = { zh, en }\n\nconst { settings } = storeToRefs(useBasicStore())\nconst { size, language } = storeToRefs(useConfigStore())\nonBeforeMount(() => {\n  //set tmp token when setting isNeedLogin false\n  if (!settings.value.isNeedLogin) useBasicStore().setToken(settings.value.tmpToken)\n})\nonMounted(() => {\n  //lanch the errorLog collection\n  useErrorLog()\n})\nconst route = useRoute()\nonMounted(() => {\n  const { setTheme, theme, setSize, size, setLanguage, language } = useConfigStore()\n  setTheme(theme)\n  setLanguage(language, route.meta?.title)\n  setSize(size)\n  toggleHtmlClass(theme)\n})\n</script>\n<style lang=\"scss\">\n//修改进度条样式\n#nprogress .bar {\n  background: var(--pregress-bar-color) !important;\n}\n</style>\n"
  },
  {
    "path": "src/api/user.ts",
    "content": "//获取用户信息\nimport axiosReq from 'axios'\n// export const userInfoReq = (): Promise<any> => {\n//   return new Promise((resolve) => {\n//     const reqConfig = {\n//       url: '/basis-func/user/getUserInfo',\n//       params: { plateFormId: 2 },\n//       method: 'post'\n//     }\n//     axiosReq(reqConfig).then(({ data }) => {\n//       resolve(data)\n//     })\n//   })\n// }\n\n//登录\nexport const loginReq = (subForm) => {\n  return axiosReq({\n    url: '/mock/login',\n    params: subForm,\n    method: 'post'\n  })\n}\n\n//退出登录\nexport const loginOutReq = () => {\n  return axiosReq({\n    url: '/mock/loginOut',\n    method: 'post'\n  })\n}\n"
  },
  {
    "path": "src/components/ElSvgIcon.vue",
    "content": "<template>\n  <el-icon :size=\"size\" :color=\"color\">\n    <component :is=\"ElSvg[name]\" />\n  </el-icon>\n</template>\n\n<script setup lang=\"ts\">\nimport * as ElSvg from '@element-plus/icons-vue'\nconst props = defineProps({\n  name: {\n    require: true,\n    default: 'Fold',\n    type: String\n  },\n  size: {\n    require: false,\n    default: 18,\n    type: Number\n  },\n  color: {\n    require: false,\n    default: '',\n    type: String\n  }\n})\n</script>\n\n<style scoped lang=\"scss\">\n//.el-svg-icon {\n//  width: 1em;\n//  height: 1em;\n//  margin-left: -2px; //el-svg-icon has some margin\n//  font-size: 20px !important;\n//  text-align: left !important;\n//}\n</style>\n"
  },
  {
    "path": "src/components/TestUnit.vue",
    "content": "<template>\n  <div>TestUnit.vue</div>\n</template>\n\n<script setup lang=\"ts\">\nconst props = defineProps({\n  msg: {\n    require: true,\n    default: 'fai',\n    type: String\n  }\n})\n</script>\n\n<style scoped lang=\"scss\"></style>\n"
  },
  {
    "path": "src/components/__tests__/el-svgIcon.test.jsx",
    "content": "import { markRaw, nextTick, ref } from 'vue'\nimport { mount } from '@vue/test-utils'\nimport { describe, expect, it, test } from 'vitest'\nimport { Loading, Search } from '@element-plus/icons-vue'\n\nimport ElSvgIcon from '../ElSvgIcon.vue'\n\n// const AXIOM = 'Rem is the best girl'\n\ndescribe('ElSvgIcon.vue', () => {\n  it('create', () => {\n    const wrapper = mount(() => <ElSvgIcon name=\"Edit\" size={30} color={'red'} />)\n    // console.log(111111, wrapper.classes())\n    // expect(wrapper.classes()).toContain('el-icon')\n  })\n\n  // it('icon', () => {\n  //   const wrapper = mount(() => <ElSvgIcon icon={markRaw(Search)} />)\n  //   expect(wrapper.findAll('Search11222')).toBeTruthy()\n  // })\n  //\n  // it('size', () => {\n  //   const wrapper = mount(() => <ElSvgIcon size=\"20px\" />)\n  //   expect(wrapper.findAll('20px')).toBeTruthy()\n  // })\n  //\n  // it('color', () => {\n  //   const wrapper = mount(() => <ElSvgIcon color={'red'} />)\n  //   expect(wrapper.findAll('red')).toBeTruthy()\n  // })\n  //\n  // it('nativeType', () => {\n  //   const wrapper = mount(() => <ElSvgIcon nativeType=\"submit\" />)\n  //\n  //   expect(wrapper.attributes('type')).toBe('submit')\n  // })\n  //\n  // it('loading', () => {\n  //   const wrapper = mount(() => <ElSvgIcon loading />)\n  //\n  //   expect(wrapper.classes()).toContain('is-loading')\n  //   expect(wrapper.findComponent(Loading).exists()).toBeTruthy()\n  // })\n  //\n  // it('size', () => {\n  //   const wrapper = mount(() => <ElSvgIcon size=\"large\" />)\n  //\n  //   expect(wrapper.classes()).toContain('el-button--large')\n  // })\n  //\n  // it('plain', () => {\n  //   const wrapper = mount(() => <ElSvgIcon plain />)\n  //\n  //   expect(wrapper.classes()).toContain('is-plain')\n  // })\n  //\n  // it('round', () => {\n  //   const wrapper = mount(() => <ElSvgIcon round />)\n  //   expect(wrapper.classes()).toContain('is-round')\n  // })\n  //\n  // it('circle', () => {\n  //   const wrapper = mount(() => <ElSvgIcon circle />)\n  //\n  //   expect(wrapper.classes()).toContain('is-circle')\n  // })\n\n  // it('text', async () => {\n  //   const bg = ref(false)\n  //\n  //   const wrapper = mount(() => <ElSvgIcon text bg={bg.value} />)\n  //\n  //   expect(wrapper.classes()).toContain('is-text')\n  //\n  //   bg.value = true\n  //\n  //   await nextTick()\n  //\n  //   expect(wrapper.classes()).toContain('is-has-bg')\n  // })\n\n  // it('link', async () => {\n  //   const wrapper = mount(() => <ElSvgIcon link />)\n  //\n  //   expect(wrapper.classes()).toContain('is-link')\n  // })\n\n  // test('render text', () => {\n  //   const wrapper = mount(() => (\n  //     <ElSvgIcon\n  //       v-slots={{\n  //         default: () => AXIOM\n  //       }}\n  //     />\n  //   ))\n  //\n  //   expect(wrapper.text()).toEqual(AXIOM)\n  // })\n  //\n  // test('handle click', async () => {\n  //   const wrapper = mount(() => (\n  //     <ElSvgIcon\n  //       v-slots={{\n  //         default: () => AXIOM\n  //       }}\n  //     />\n  //   ))\n  //\n  //   await wrapper.trigger('click')\n  //   expect(wrapper.emitted()).toBeDefined()\n  // })\n  //\n  // test('handle click inside', async () => {\n  //   const wrapper = mount(() => (\n  //     <ElSvgIcon\n  //       v-slots={{\n  //         default: () => <span class=\"inner-slot\"></span>\n  //       }}\n  //     />\n  //   ))\n  //\n  //   wrapper.find('.inner-slot').trigger('click')\n  //   expect(wrapper.emitted()).toBeDefined()\n  // })\n  //\n  // test('loading implies disabled', async () => {\n  //   const wrapper = mount(() => (\n  //     <ElSvgIcon\n  //       v-slots={{\n  //         default: () => AXIOM\n  //       }}\n  //       loading\n  //     />\n  //   ))\n  //\n  //   await wrapper.trigger('click')\n  //   expect(wrapper.emitted('click')).toBeUndefined()\n  // })\n  //\n  // it('disabled', async () => {\n  //   const wrapper = mount(() => <ElSvgIcon disabled />)\n  //\n  //   expect(wrapper.classes()).toContain('is-disabled')\n  //   await wrapper.trigger('click')\n  //   expect(wrapper.emitted('click')).toBeUndefined()\n  // })\n  //\n  // it('loading icon', () => {\n  //   const wrapper = mount(() => <ElSvgIcon loadingIcon={markRaw(Search)} loading />)\n  //\n  //   expect(wrapper.findComponent(Search).exists()).toBeTruthy()\n  // })\n  //\n  // it('loading slot', () => {\n  //   const wrapper = mount({\n  //     setup: () => () => (\n  //       <ElSvgIcon v-slots={{ loading: () => <span class=\"custom-loading\">111</span> }} loading={true}>\n  //         Loading\n  //       </ElSvgIcon>\n  //     )\n  //   })\n  //\n  //   expect(wrapper.find('.custom-loading').exists()).toBeTruthy()\n  // })\n})\n// describe('ElSvgIcon Group', () => {\n//   it('create', () => {\n//     const wrapper = mount({\n//       setup: () => () =>\n//         (\n//           <ButtonGroup>\n//             <ElSvgIcon type=\"primary\">Prev</ElSvgIcon>\n//             <ElSvgIcon type=\"primary\">Next</ElSvgIcon>\n//           </ButtonGroup>\n//         )\n//     })\n//     expect(wrapper.classes()).toContain('el-button-group')\n//     expect(wrapper.findAll('button').length).toBe(2)\n//   })\n//\n//   it('button group reactive size', async () => {\n//     const size = ref<ComponentSize>('small')\n//     const wrapper = mount({\n//       setup: () => () =>\n//         (\n//           <ButtonGroup size={size.value}>\n//             <ElSvgIcon type=\"primary\">Prev</ElSvgIcon>\n//             <ElSvgIcon type=\"primary\">Next</ElSvgIcon>\n//           </ButtonGroup>\n//         )\n//     })\n//     expect(wrapper.classes()).toContain('el-button-group')\n//     expect(wrapper.findAll('.el-button-group button.el-button--small').length).toBe(2)\n//\n//     size.value = 'large'\n//     await nextTick()\n//\n//     expect(wrapper.findAll('.el-button-group button.el-button--large').length).toBe(2)\n//   })\n//\n//   it('button group type', async () => {\n//     const wrapper = mount({\n//       setup: () => () =>\n//         (\n//           <ButtonGroup type=\"warning\">\n//             <ElSvgIcon type=\"primary\">Prev</ElSvgIcon>\n//             <ElSvgIcon>Next</ElSvgIcon>\n//           </ButtonGroup>\n//         )\n//     })\n//     expect(wrapper.classes()).toContain('el-button-group')\n//     expect(wrapper.findAll('.el-button-group button.el-button--primary').length).toBe(1)\n//     expect(wrapper.findAll('.el-button-group button.el-button--warning').length).toBe(1)\n//   })\n//\n//   it('add space in two Chinese characters', async () => {\n//     const wrapper = mount(() => (\n//       <ElSvgIcon\n//         v-slots={{\n//           default: () => '中文'\n//         }}\n//         autoInsertSpace\n//       />\n//     ))\n//\n//     expect(wrapper.find('.el-button span').text()).toBe('中文')\n//     expect(wrapper.find('.el-button span').classes()).toContain('el-button__text--expand')\n//   })\n//\n//   it('add space between two Chinese characters even if there is whitespace at both ends', async () => {\n//     const wrapper = mount(() => <ElSvgIcon autoInsertSpace>&nbsp;中文&nbsp;</ElSvgIcon>)\n//\n//     expect(wrapper.find('.el-button span').text()).toBe('中文')\n//     expect(wrapper.find('.el-button span').classes()).toContain('el-button__text--expand')\n//   })\n// })\n"
  },
  {
    "path": "src/directives/button-codes.ts",
    "content": "import { useBasicStore } from '@/store/basic'\n\nfunction checkPermission(el, { value }) {\n  if (value && Array.isArray(value)) {\n    if (value.length) {\n      const permissionRoles = value\n      const hasPermission = useBasicStore().buttonCodes?.some((code) => permissionRoles.includes(code))\n      if (!hasPermission) el.parentNode && el.parentNode.removeChild(el)\n    }\n  } else {\n    throw new Error(`need roles! Like v-permission=\"['admin','editor']\"`)\n  }\n}\nexport default {\n  mounted(el, binding) {\n    checkPermission(el, binding)\n  },\n  componentUpdated(el, binding) {\n    checkPermission(el, binding)\n  }\n}\n"
  },
  {
    "path": "src/directives/codes-permission.ts",
    "content": "import { useBasicStore } from '@/store/basic'\nfunction checkPermission(el, { value }) {\n  if (value && Array.isArray(value)) {\n    if (value.length > 0) {\n      const permissionRoles = value\n      const hasPermission = useBasicStore().codes?.some((role) => permissionRoles.includes(role))\n      if (!hasPermission) el.parentNode && el.parentNode.removeChild(el)\n    }\n  } else {\n    throw new Error(`need codes! Like v-codes-permission=\"['admin','editor']\"`)\n  }\n}\nexport default {\n  mounted(el, binding) {\n    checkPermission(el, binding)\n  },\n  componentUpdated(el, binding) {\n    checkPermission(el, binding)\n  }\n}\n"
  },
  {
    "path": "src/directives/index.ts",
    "content": "import buttonCodes from './button-codes'\nimport codesPermission from './codes-permission'\nimport rolesPermission from './roles-permission'\nimport lang from './lang'\nexport default function (app) {\n  app.directive('ButtonCodes', buttonCodes)\n  app.directive('CodesPermission', codesPermission)\n  app.directive('RolesPermission', rolesPermission)\n  app.directive('lang', lang)\n}\n"
  },
  {
    "path": "src/directives/lang.ts",
    "content": "import { watch } from 'vue'\nimport { storeToRefs } from 'pinia/dist/pinia'\nimport { langTitle } from '@/hooks/use-common'\nimport { useConfigStore } from '@/store/config'\n//element-plus\nconst componentToProps = {\n  ElInput: 'placeholder',\n  ElTableColumn: 'label'\n}\n\nfunction checkPermission(el, { value }) {\n  let saveOriginTitle = ''\n  const { language } = storeToRefs(useConfigStore())\n  //save the original title\n  const name = el.__vueParentComponent?.type?.name\n  const nameTitle = el.__vueParentComponent?.props[componentToProps[name]]\n  saveOriginTitle = nameTitle || el.innerText\n  watch(\n    () => language.value,\n    () => {\n      //element tag or component\n      if (name?.startsWith('EL')) {\n        //self cunstrom\n        if (Object.keys(componentToProps).includes(name)) {\n          const props = el.__vueParentComponent.props\n          props[componentToProps[name]] = langTitle(saveOriginTitle)\n        } else {\n          el.innerText = langTitle(saveOriginTitle)\n        }\n      } else {\n        //common tag such as div span output so on;\n        if (el.__vnode?.type) {\n          el.innerText = langTitle(saveOriginTitle)\n        }\n      }\n    },\n    { immediate: true }\n  )\n}\nexport default {\n  mounted(el, binding) {\n    checkPermission(el, binding)\n  }\n}\n"
  },
  {
    "path": "src/directives/roles-permission.ts",
    "content": "import { useBasicStore } from '@/store/basic'\nfunction checkPermission(el, { value }) {\n  if (value && Array.isArray(value)) {\n    if (value.length > 0) {\n      const permissionRoles = value\n      const hasPermission = useBasicStore().roles?.some((role) => permissionRoles.includes(role))\n      if (!hasPermission) el.parentNode && el.parentNode.removeChild(el)\n    }\n  } else {\n    throw new Error(`need roles! Like v-roles-permission=\"['admin','editor']\"`)\n  }\n}\nexport default {\n  mounted(el, binding) {\n    checkPermission(el, binding)\n  },\n  componentUpdated(el, binding) {\n    checkPermission(el, binding)\n  }\n}\n"
  },
  {
    "path": "src/hooks/use-common.ts",
    "content": "//复制文本\nimport useClipboard from 'vue-clipboard3'\nimport { ElMessage } from 'element-plus'\n\n// i18n language  match title\nimport { i18n } from '@/lang'\n// the keys using  zh file\nimport langEn from '@/lang/zh'\nimport settings from '@/settings'\n\nexport const sleepTimeout = (time: number) => {\n  return new Promise((resolve) => {\n    const timer = setTimeout(() => {\n      clearTimeout(timer)\n      resolve(null)\n    }, time)\n  })\n}\n\n//深拷贝\nexport function cloneDeep(value) {\n  return JSON.parse(JSON.stringify(value))\n}\n\n//copyValueToClipboard\nconst { toClipboard } = useClipboard()\nexport const copyValueToClipboard = (value: any) => {\n  toClipboard(JSON.stringify(value))\n  ElMessage.success('复制成功')\n}\nconst { t, te } = i18n.global\nexport const langTitle = (title) => {\n  if (!title) {\n    return settings.title\n  }\n  for (const key of Object.keys(langEn)) {\n    if (te(`${key}.${title}`) && t(`${key}.${title}`)) {\n      return t(`${key}.${title}`)\n    }\n  }\n  return title\n}\n\n//get i18n instance\nexport const getLangInstance = () => {\n  return i18n.global as ObjKeys\n}\n"
  },
  {
    "path": "src/hooks/use-element.ts",
    "content": "import { reactive, ref, toRefs } from 'vue'\nimport { ElLoading, ElMessage, ElMessageBox, ElNotification } from 'element-plus'\nimport type { EpPropMergeType } from 'element-plus/es/utils'\nexport const useElement = () => {\n  // 正整数\n  const upZeroInt = (rule, value, callback, msg) => {\n    if (!value) {\n      callback(new Error(`${msg}不能为空`))\n    }\n    if (/^\\+?[1-9]\\d*$/.test(value)) {\n      callback()\n    } else {\n      callback(new Error(`${msg}输入有误`))\n    }\n  }\n\n  // 正整数（包括0）\n  const zeroInt = (rule, value, callback, msg) => {\n    if (!value) {\n      callback(new Error(`${msg}不能为空`))\n    }\n    if (/^\\+?[0-9]\\d*$/.test(value)) {\n      callback()\n    } else {\n      callback(new Error(`${msg}输入有误`))\n    }\n  }\n\n  // 金额\n  const money = (rule, value, callback, msg) => {\n    if (!value) {\n      callback(new Error(`${msg}不能为空`))\n    }\n    if (/((^[1-9]\\d*)|^0)(\\.\\d{0,2}){0,1}$/.test(value)) {\n      callback()\n    } else {\n      callback(new Error(`${msg}输入有误`))\n    }\n  }\n\n  // 手机号\n  const phone = (rule, value, callback, msg) => {\n    if (!value) {\n      callback(new Error(`${msg}不能为空`))\n    }\n    if (/^0?1[0-9]{10}$/.test(value)) {\n      callback()\n    } else {\n      callback(new Error(`${msg}输入有误`))\n    }\n  }\n\n  // 邮箱\n  const email = (rule, value, callback, msg) => {\n    if (!value) {\n      callback(new Error(`${msg}不能为空`))\n    }\n    if (/(^([a-zA-Z]|[0-9])(\\w|-)+@[a-zA-Z0-9]+\\.([a-zA-Z]{2,4}))$/.test(value)) {\n      callback()\n    } else {\n      callback(new Error(`${msg}`))\n    }\n  }\n  const state = reactive({\n    /* table*/\n    tableData: [],\n    rowDeleteIdArr: [],\n    loadingId: null,\n    /* 表单*/\n    formModel: {},\n    subForm: {},\n    searchForm: {},\n    /* 表单校验*/\n    formRules: {\n      //非空\n      isNull: (msg: string) => [{ required: false, message: `${msg}`, trigger: 'blur' }],\n      isNotNull: (msg: string) => [{ required: true, message: `${msg}`, trigger: 'blur' }],\n      // 正整数\n      upZeroInt: (msg: string) => [\n        { required: true, validator: (rule, value, callback) => upZeroInt(rule, value, callback, msg), trigger: 'blur' }\n      ],\n      // 正整数（包括0）\n      zeroInt: (msg: string) => [\n        { required: true, validator: (rule, value, callback) => zeroInt(rule, value, callback, msg), trigger: 'blur' }\n      ],\n      // 金额\n      money: (msg: string) => [\n        { required: true, validator: (rule, value, callback) => money(rule, value, callback, msg), trigger: 'blur' }\n      ],\n      // 手机号\n      phone: (msg: string) => [\n        { required: true, validator: (rule, value, callback) => phone(rule, value, callback, msg), trigger: 'blur' }\n      ],\n      // 邮箱\n      email: (msg: string) => [\n        { required: true, validator: (rule, value, callback) => email(rule, value, callback, msg), trigger: 'blur' }\n      ]\n    },\n    /* 时间packing相关*/\n    datePickerOptions: {\n      //选择今天以后的日期，包括今天\n      disabledDate: (time: any) => {\n        return time.getTime() < Date.now() - 86400000\n      }\n    },\n    startEndArr: [],\n    /* dialog相关*/\n    dialogTitle: '添加',\n    detailDialog: false,\n    isDialogEdit: false,\n    dialogVisible: false,\n    tableLoading: false,\n    /* 树相关*/\n    treeData: [],\n    defaultProps: {\n      children: 'children',\n      label: 'label'\n    }\n  })\n  return {\n    ...toRefs(state)\n  }\n}\n\n/*\n * 通知弹框\n * message：通知的内容\n * type：通知类型\n * duration：通知显示时长（ms）\n * */\nexport const elMessage = (message: string, type?) => {\n  ElMessage({\n    showClose: true,\n    message: message || '成功',\n    type: type || ('success' as string),\n    center: false\n  })\n}\n/*\n * loading加载框\n * 调用后通过 loadingId.close() 进行关闭\n * */\nlet loadingId: any = null\nexport const elLoading = (msg?: string) => {\n  loadingId = ElLoading.service({\n    lock: true,\n    text: msg || '数据载入中',\n    // spinner: 'el-icon-loading',\n    background: 'rgba(0, 0, 0, 0.1)'\n  })\n}\nexport const closeElLoading = () => {\n  loadingId.close()\n}\n/*\n * 提示\n * message: 提示内容\n * type：提示类型\n * title：提示标题\n * duration：提示时长（ms）\n * */\nexport const elNotify = (\n  message: string,\n  type: EpPropMergeType<any, any, any> | undefined,\n  title: string,\n  duration: number\n) => {\n  ElNotification({\n    title: title || '提示',\n    type: type || 'success',\n    message: message || '请传入提示消息',\n    position: 'top-right',\n    duration: duration || 2500,\n    offset: 40\n  })\n}\n/*\n  确认弹框(没有取消按钮)\n* title:提示的标题\n* message:提示的内容\n* return Promise\n* */\nexport const elConfirmNoCancelBtn = (title: string, message: string) => {\n  return ElMessageBox({\n    message: message || '你确定要删除吗',\n    title: title || '确认框',\n    confirmButtonText: '确定',\n    cancelButtonText: '取消',\n    showCancelButton: false,\n    type: 'warning'\n  })\n}\n/*\n * 确认弹框\n * title:提示的标题\n * message:提示的内容\n * return Promise\n * */\nexport const elConfirm = (title: string, message: string) => {\n  return ElMessageBox({\n    message: message || '你确定要删除吗',\n    title: title || '确认框',\n    confirmButtonText: '确定',\n    cancelButtonText: '取消',\n    type: 'warning'\n  })\n}\n\n/* 级联*/\nconst cascaderKey = ref()\nexport const casHandleChange = () => {\n  // 解决目前级联选择器搜索输入报错问题\n  cascaderKey.value += cascaderKey.value\n}\n"
  },
  {
    "path": "src/hooks/use-error-log.ts",
    "content": "/*js 错误日志收集*/\nimport { jsErrorCollection } from 'js-error-collection'\nimport axiosReq from 'axios'\nimport pack from '../../package.json'\nimport settings from '@/settings'\nimport bus from '@/utils/bus'\n//此处不要使用utils下的axios\nconst reqUrl = '/integration-front/errorCollection/insert'\nlet repeatErrorLogJudge = ''\nconst errorLogReq = (errLog: string) => {\n  axiosReq({\n    url: import.meta.env.VITE_APP_BASE_URL+reqUrl,\n    data: {\n      pageUrl: window.location.href,\n      errorLog: errLog,\n      browserType: navigator.userAgent,\n      version: pack.version\n    },\n    method: 'post'\n  }).then(() => {\n    //通知错误列表页面更新数据\n    bus.emit('reloadErrorPage', {})\n  })\n}\n\nexport const useErrorLog = () => {\n  //判断该环境是否需要收集错误日志,由settings配置决定\n  if (settings.errorLog?.includes(import.meta.env.VITE_APP_ENV)) {\n    jsErrorCollection({ runtimeError: true, rejectError: true, consoleError: true }, (errLog) => {\n      if (!repeatErrorLogJudge || !errLog.includes(repeatErrorLogJudge)) {\n        errorLogReq(errLog)\n        //移除重复日志，fix重复提交错误日志，避免造成死循环\n        repeatErrorLogJudge = errLog.slice(0, 20)\n      }\n    })\n  }\n}\n"
  },
  {
    "path": "src/hooks/use-layout.ts",
    "content": "/**\n * 判断是否是外链\n * @param {string} path\n * @returns {Boolean}\n */\nimport { onBeforeMount, onBeforeUnmount, onMounted } from 'vue'\nimport { useBasicStore } from '@/store/basic'\nexport function isExternal(path) {\n  return /^(https?:|mailto:|tel:)/.test(path)\n}\n\n/*判断窗口变化控制侧边栏收起或展开*/\nexport function resizeHandler() {\n  const { body } = document\n  const WIDTH = 992\n  const basicStore = useBasicStore()\n  const isMobile = () => {\n    const rect = body.getBoundingClientRect()\n    return rect.width - 1 < WIDTH\n  }\n  const resizeHandler = () => {\n    if (!document.hidden) {\n      if (isMobile()) {\n        /*此处只做根据window尺寸关闭sideBar功能*/\n        basicStore.setSidebarOpen(false)\n      } else {\n        basicStore.setSidebarOpen(true)\n      }\n    }\n  }\n  onBeforeMount(() => {\n    window.addEventListener('resize', resizeHandler)\n  })\n  onMounted(() => {\n    if (isMobile()) {\n      basicStore.setSidebarOpen(false)\n    } else {\n      basicStore.setSidebarOpen(true)\n    }\n  })\n  onBeforeUnmount(() => {\n    window.removeEventListener('resize', resizeHandler)\n  })\n}\n"
  },
  {
    "path": "src/hooks/use-permission.ts",
    "content": "import NProgress from 'nprogress'\nimport type { RouteRawConfig, RouterTypes, rawConfig } from '~/basic'\nimport type { RouteRecordName } from 'vue-router'\n/**\n * 根据请求，过滤异步路由\n * @param:menuList 异步路由数组\n * return 过滤后的异步路由\n */\n// @ts-ignore\nimport Layout from '@/layout/index.vue'\n/*\n * 路由操作\n * */\nimport router, { asyncRoutes, constantRoutes, roleCodeRoutes } from '@/router'\n//进度条\nimport 'nprogress/nprogress.css'\nimport { useBasicStore } from '@/store/basic'\n\nconst buttonCodes: Array<Number> = [] //按钮权限\ninterface menuRow {\n  category: number\n  code: number\n  children: RouterTypes\n}\nexport const filterAsyncRoutesByMenuList = (menuList) => {\n  const filterRouter: RouterTypes = []\n  menuList.forEach((route: menuRow) => {\n    //button permission\n    if (route.category === 3) {\n      buttonCodes.push(route.code)\n    } else {\n      //generator every router item by menuList\n      const itemFromReqRouter = getRouteItemFromReqRouter(route)\n      if (route.children?.length) {\n        //judge  the type is router or button\n        itemFromReqRouter.children = filterAsyncRoutesByMenuList(route.children)\n      }\n      filterRouter.push(itemFromReqRouter)\n    }\n  })\n  return filterRouter\n}\nconst getRouteItemFromReqRouter = (route): RouteRawConfig => {\n  const tmp: rawConfig = { meta: { title: '' } }\n  const routeKeyArr = ['path', 'component', 'redirect', 'alwaysShow', 'name', 'hidden']\n  const metaKeyArr = ['title', 'activeMenu', 'elSvgIcon', 'icon']\n  // @ts-ignore\n  const modules = import.meta.glob('../views/**/**.vue')\n  //generator routeKey\n  routeKeyArr.forEach((fItem) => {\n    if (fItem === 'component') {\n      if (route[fItem] === 'Layout') {\n        tmp[fItem] = Layout\n      } else {\n        //has error , i will fix it through plugins\n        //tmp[fItem] = () => import(`@/views/permission-center/test/TestTableQuery.vue`)\n        tmp[fItem] = modules[`../views/${route[fItem]}`]\n      }\n    } else if (fItem === 'path' && route.parentId === 0) {\n      tmp[fItem] = `/${route[fItem]}`\n    } else if (['hidden', 'alwaysShow'].includes(fItem)) {\n      tmp[fItem] = !!route[fItem]\n    } else if (['name'].includes(fItem)) {\n      tmp[fItem] = route['code']\n    } else if (route[fItem]) {\n      tmp[fItem] = route[fItem]\n    }\n  })\n  //generator metaKey\n  metaKeyArr.forEach((fItem) => {\n    if (route[fItem] && tmp.meta) tmp.meta[fItem] = route[fItem]\n  })\n  //route extra insert\n  if (route.extra) {\n    Object.entries(route.extra.parse(route.extra)).forEach(([key, value]) => {\n      if (key === 'meta' && tmp.meta) {\n        tmp.meta[key] = value\n      } else {\n        tmp[key] = value\n      }\n    })\n  }\n  return tmp as RouteRawConfig\n}\n\n/**\n * 根据角色数组过滤异步路由\n * @param routes asyncRoutes 未过滤的异步路由\n * @param roles  角色数组\n * return 过滤后的异步路由\n */\nexport function filterAsyncRoutesByRoles(routes, roles) {\n  const res: RouterTypes = []\n  routes.forEach((route) => {\n    const tmp: RouteRawConfig = { ...route }\n    if (hasPermission(roles, tmp)) {\n      if (tmp.children) {\n        tmp.children = filterAsyncRoutesByRoles(tmp.children, roles)\n      }\n      res.push(tmp)\n    }\n  })\n  return res\n}\nfunction hasPermission(roles, route) {\n  if (route?.meta?.roles) {\n    return roles?.some((role) => route.meta.roles.includes(role))\n  } else {\n    return true\n  }\n}\n\n/**\n * 根据code数组，过滤异步路由\n * @param codes code数组\n * @param codesRoutes 未过滤的异步路由\n * return 过滤后的异步路由\n */\nexport function filterAsyncRouterByCodes(codesRoutes, codes) {\n  const filterRouter: RouterTypes = []\n  codesRoutes.forEach((routeItem: RouteRawConfig) => {\n    if (hasCodePermission(codes, routeItem)) {\n      if (routeItem.children) routeItem.children = filterAsyncRouterByCodes(routeItem.children, codes)\n      filterRouter.push(routeItem)\n    }\n  })\n  return filterRouter\n}\nfunction hasCodePermission(codes, routeItem) {\n  if (routeItem.meta?.code) {\n    return codes.includes(routeItem.meta.code) || routeItem.hidden\n  } else {\n    return true\n  }\n}\n//过滤异步路由\nexport function filterAsyncRouter({ menuList, roles, codes }) {\n  const basicStore = useBasicStore()\n  let accessRoutes: RouterTypes = []\n  const permissionMode = basicStore.settings?.permissionMode\n  if (permissionMode === 'rbac') {\n    accessRoutes = filterAsyncRoutesByMenuList(menuList) //by menuList\n  } else if (permissionMode === 'roles') {\n    accessRoutes = filterAsyncRoutesByRoles(roleCodeRoutes, roles) //by roles\n  } else {\n    accessRoutes = filterAsyncRouterByCodes(roleCodeRoutes, codes) //by codes\n  }\n  accessRoutes.forEach((route) => router.addRoute(route))\n  asyncRoutes.forEach((item) => router.addRoute(item))\n  basicStore.setFilterAsyncRoutes(accessRoutes)\n}\n//重置路由\nexport function resetRouter() {\n  //移除之前存在的路由\n  const routeNameSet: Set<RouteRecordName> = new Set()\n  router.getRoutes().forEach((fItem) => {\n    if (fItem.name) routeNameSet.add(fItem.name)\n  })\n  routeNameSet.forEach((setItem) => router.removeRoute(setItem))\n  //新增constantRoutes\n  constantRoutes.forEach((feItem) => router.addRoute(feItem))\n}\n//重置登录状态\nexport function resetState() {\n  resetRouter()\n  useBasicStore().resetState()\n}\n\n//刷新路由\nexport function freshRouter(data) {\n  resetRouter()\n  filterAsyncRouter(data)\n  // location.reload()\n}\n\nNProgress.configure({ showSpinner: false })\n//开始进度条\nexport const progressStart = () => {\n  NProgress.start()\n}\n//关闭进度条\nexport const progressClose = () => {\n  NProgress.done()\n}\n"
  },
  {
    "path": "src/hooks/use-self-router.ts",
    "content": "import router from '@/router'\nexport const getQueryParam = () => {\n  const route: any = router.currentRoute\n  if (route.value?.query.params) {\n    return JSON.parse(route.value.query.params)\n  }\n}\n// vue router\nexport const routerPush = (name, params) => {\n  let data = {}\n  if (params) {\n    data = {\n      params: JSON.stringify(params)\n    }\n  } else {\n    data = {}\n  }\n  router.push({\n    name,\n    query: data\n  })\n}\nexport const routerReplace = (name, params) => {\n  let data = {}\n  if (params) {\n    data = {\n      params: JSON.stringify(params)\n    }\n  } else {\n    data = {}\n  }\n  router.replace({\n    name,\n    query: data\n  })\n}\n\nexport const routeInfo = () => {\n  return router.currentRoute\n}\nexport const routerBack = () => {\n  router.go(-1)\n}\n"
  },
  {
    "path": "src/hooks/use-table.ts",
    "content": "import { ref } from 'vue'\nimport momentMini from 'moment-mini'\nimport { elConfirm, elMessage } from './use-element'\nexport const useTable = (searchForm, selectPageReq) => {\n  /*define ref*/\n  const tableListData = ref([])\n  const totalPage = ref(0)\n  const pageNum = ref(1)\n  const pageSize = ref(20)\n\n  //列表请求\n  const tableListReq = (config) => {\n    const data = Object.assign(\n      {\n        pageNum: pageNum.value,\n        pageSize: pageSize.value\n      },\n      JSON.parse(JSON.stringify(searchForm))\n    )\n    Object.keys(data).forEach((fItem) => {\n      if (['', null, undefined, Number.NaN].includes(data[fItem])) delete data[fItem]\n      if (config.method === 'get') {\n        if (Array.isArray(data[fItem])) delete data[fItem]\n        if (data[fItem] instanceof Object) delete data[fItem]\n      }\n    })\n    const reqConfig = {\n      data,\n      ...config\n    }\n    return axiosReq(reqConfig)\n  }\n\n  /**\n   * 日期范围选择处理\n   * @param timeArr choose the time\n   * @author 熊猫哥\n   * @date 2022/9/25 14:02\n   */\n  const dateRangePacking = (timeArr) => {\n    if (timeArr && timeArr.length === 2) {\n      searchForm.startTime = timeArr[0]\n      //取今天23点\n      if (searchForm.endTime) {\n        searchForm.endTime = momentMini(timeArr[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss')\n      }\n    } else {\n      searchForm.startTime = ''\n      searchForm.endTime = ''\n    }\n  }\n  //当前页\n  const handleCurrentChange = (val) => {\n    pageNum.value = val\n    selectPageReq()\n  }\n  const handleSizeChange = (val) => {\n    pageSize.value = val\n    selectPageReq()\n  }\n  const resetPageReq = () => {\n    pageNum.value = 1\n    selectPageReq()\n  }\n\n  /*多选*/\n  const multipleSelection = ref<Array<ObjKeys>>([])\n  const handleSelectionChange = (val) => {\n    multipleSelection.value = val\n  }\n  /*批量删除*/\n  const multiDelBtnDill = (reqConfig) => {\n    let rowDeleteIdArr: Array<string> = []\n    let deleteNameTitle = ''\n    rowDeleteIdArr = multipleSelection.value.map((mItem) => {\n      deleteNameTitle = `${deleteNameTitle + mItem.id},`\n      return mItem.id\n    })\n    if (rowDeleteIdArr.length === 0) {\n      elMessage('表格选项不能为空', 'warning')\n      return\n    }\n    const stringLength = deleteNameTitle.length - 1\n    elConfirm('删除', `您确定要删除【${deleteNameTitle.slice(0, stringLength)}】吗`).then(() => {\n      const data = rowDeleteIdArr\n      axiosReq({\n        data,\n        method: 'DELETE',\n        bfLoading: true,\n        ...reqConfig\n      }).then(() => {\n        elMessage('删除成功')\n        resetPageReq()\n      })\n    })\n  }\n  //单个删除\n  const tableDelDill = (row, reqConfig) => {\n    elConfirm('确定', `您确定要删除【${row.id}】吗？`).then(() => {\n      axiosReq(reqConfig).then(() => {\n        resetPageReq()\n        elMessage(`【${row.id}】删除成功`)\n      })\n    })\n  }\n\n  return {\n    pageNum,\n    pageSize,\n    totalPage,\n    tableListData,\n    tableListReq,\n    dateRangePacking,\n    multipleSelection,\n    handleSelectionChange,\n    handleCurrentChange,\n    handleSizeChange,\n    resetPageReq,\n    multiDelBtnDill,\n    tableDelDill\n  }\n}\n"
  },
  {
    "path": "src/icons/SvgIcon.vue",
    "content": "<template>\n  <svg :class=\"svgClass\" aria-hidden=\"true\">\n    <use :xlink:href=\"iconName\" :fill=\"color\" />\n  </svg>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, defineComponent } from 'vue'\nconst props = defineProps({\n  iconClass: {\n    type: String,\n    required: true\n  },\n  className: {\n    type: String,\n    default: ''\n  },\n  color: {\n    type: String,\n    default: ''\n  },\n})\n\nconst iconName = computed(() => `#icon-${props.iconClass}`)\nconst svgClass = computed(() => {\n  if (props.className) {\n    return `svg-icon ${props.className}`\n  }\n  return 'svg-icon'\n})\n</script>\n\n<style scoped lang=\"scss\">\n.svg-icon {\n  width: 1em;\n  height: 1em;\n  position: relative;\n  fill: currentColor;\n  vertical-align: -2px;\n}\n</style>\n"
  },
  {
    "path": "src/lang/en.ts",
    "content": "export default {\n  router: {\n    Dashboard: '',\n    'Setting Switch': '',\n    'Error Log': '',\n    'Error Index': '',\n    'Error Generator': '',\n\n    Nested: '',\n    Menu1: '',\n    'Menu1-1': '',\n    'Menu1-2': '',\n    'Menu1-2-1': '',\n    'Menu1-2-2': '',\n    'Menu1-3': '',\n    menu2: '',\n\n    'External Link': '',\n\n    'Basic Demo': '',\n    Hook: '',\n    Pinia: '',\n    Mock: '',\n    'Svg Icon': '',\n    'Parent Children': '',\n    'KeepAlive Group': '',\n    'Tab KeepAlive': '',\n    'Third KeepAlive': '',\n    SecondChildren: '',\n    ThirdChildren: '',\n\n    Worker: '',\n\n    Permission: '',\n\n    'Permission Switch': '',\n    'Role Index': '',\n    'Code Index': '',\n    'Button Permission': ''\n  },\n  navbar: {\n    Home: '',\n    Github: '',\n    Docs: '',\n    'login out': ''\n  },\n\n  //page\n  dashboard: {\n    'switch theme': '',\n    'switch size': '',\n    'switch language': '',\n    en: 'English',\n    zh: '中文',\n    'Button Group': '',\n    'unocss using': '',\n    'global var': ''\n  },\n  'error-log': {\n    log: '',\n    pageUrl: '',\n    startDate: '',\n    endDate: '',\n    github: '',\n    search: '',\n    reset: '',\n    multiDel: ''\n  },\n  permission: {\n    addRole: '',\n    editPermission: '',\n    roles: '',\n    switchRoles: '',\n    tips:\n      '在某些情况下，不适合使用 v-permission。例如：Element-UI 的 el-tab 或 el-table-column 以及其它动态渲染 dom 的场景。你只能通过手动设置 v-if 来实现。',\n    delete: '删除',\n    confirm: '确定',\n    cancel: '取消'\n  },\n  guide: {\n    description: '引导页对于一些第一次进入项目的人很有用，你可以简单介绍下项目的功能。本 Demo 是基于',\n    button: '打开引导'\n  },\n  components: {\n    documentation: '文档',\n    tinymceTips:\n      '富文本是管理后台一个核心的功能，但同时又是一个有很多坑的地方。在选择富文本的过程中我也走了不少的弯路，市面上常见的富文本都基本用过了，最终权衡了一下选择了Tinymce。更详细的富文本比较和介绍见',\n    dropzoneTips:\n      '由于我司业务有特殊需求，而且要传七牛 所以没用第三方，选择了自己封装。代码非常的简单，具体代码你可以在这里看到 @/components/Dropzone',\n    stickyTips: '当页面滚动到预设的位置会吸附在顶部',\n    backToTopTips1: '页面滚动到指定位置会在右下角出现返回顶部按钮',\n    backToTopTips2:\n      '可自定义按钮的样式、show/hide、出现的高度、返回的位置 如需文字提示，可在外部使用Element的el-tooltip元素',\n    imageUploadTips:\n      '由于我在使用时它只有vue@1版本，而且和mockjs不兼容，所以自己改造了一下，如果大家要使用的话，优先还是使用官方版本。'\n  },\n  table: {\n    dynamicTips1: '固定表头, 按照表头顺序排序',\n    dynamicTips2: '不固定表头, 按照点击顺序排序',\n    dragTips1: '默认顺序',\n    dragTips2: '拖拽后顺序',\n    title: '标题',\n    importance: '重要性',\n    type: '类型',\n    remark: '点评',\n    search: '搜索',\n    add: '添加',\n    export: '导出',\n    reviewer: '审核人',\n    id: '序号',\n    date: '时间',\n    author: '作者',\n    readings: '阅读数',\n    status: '状态',\n    actions: '操作',\n    edit: '编辑',\n    publish: '发布',\n    draft: '草稿',\n    delete: '删除',\n    cancel: '取 消',\n    confirm: '确 定'\n  }\n}\n"
  },
  {
    "path": "src/lang/index.ts",
    "content": "import { createI18n } from 'vue-i18n'\nimport en from './en'\nimport zh from './zh'\nimport settings from '@/settings'\nconst messages = { en, zh }\n\nconst localeData = {\n  globalInjection: true, //如果设置true, $t() 函数将注册到全局\n  legacy: false, //如果想在composition api中使用需要设置为false\n  locale: settings.defaultLanguage,\n  messages // set locale messages\n}\n\nexport const i18n = createI18n(localeData)\nexport const setupI18n = {\n  install(app) {\n    app.use(i18n)\n  }\n}\n"
  },
  {
    "path": "src/lang/zh.ts",
    "content": "export default {\n  router: {\n    Dashboard: '首页',\n    LowCodePlatFrom: '低代码平台',\n    RBAC: '用户权限角色',\n    'Setting Switch': '配置文件',\n    'Error Log': '错误日志',\n    'Error Index': '错误日志列表',\n    'Error Generator': '错误日志生成',\n\n    Nested: '路由嵌套',\n    Menu1: '菜单1',\n    'Menu1-1': '菜单 1-1',\n    'Menu1-2': '菜单 1-2',\n    'Menu1-2-1': '菜单 1-2-1',\n    'Menu1-2-2': '菜单 1-2-2',\n    'Menu1-3': '菜单 1-3',\n    menu2: '菜单 2',\n\n    'External Link': '外链',\n\n    'Basic Demo': '基础例子',\n    Hook: 'hook',\n    Pinia: 'pinia',\n    Mock: 'mock',\n    'Svg Icon': 'svg使用',\n    'Parent Children': '父子组件通信',\n    'KeepAlive Group': '缓存组',\n    'Tab KeepAlive': 'tab缓存',\n    'Third KeepAlive': '三级路由缓存',\n    SecondChildren: '三级路由示例1',\n    ThirdChildren: '三级路由示例2',\n    Worker: '多线程',\n    Permission: '权限路由',\n    'Permission Switch': '权限切换',\n    'Role Index': '角色权限',\n    'Code Index': 'Code权限',\n    'Button Permission': '按钮权限',\n\n    Charts: '图表',\n    Excel: 'Excel',\n    'Rich Text': '富文本',\n    Table: '表格',\n    Guid: '使用引导',\n    Other: '其他'\n  },\n\n  tagsView: {\n    Refresh: '刷新',\n    Close: '关闭当前',\n    'Close Others': '关闭其他',\n    'Close All': '关闭所有'\n  },\n  navbar: {\n    Home: '首页',\n    Github: '项目git地址',\n    Docs: '官方文档',\n    'login out': '退出登录'\n  },\n  //page\n  dashboard: {\n    'switch theme': '切换主题色',\n    'switch size': '切换尺寸',\n    'switch language': '切换语言',\n    en: 'English',\n    zh: '中文',\n    'Button Group': '按钮组',\n    'unocss using': 'unocss使用',\n    'global var': '全局静态变量'\n  },\n  'error-log': {\n    log: '错误日志',\n    pageUrl: '页面路径',\n    startDate: '开始日期',\n    endDate: '结束日期',\n    github: 'Github 地址',\n    search: '查询',\n    reset: '重置',\n    multiDel: '批量删除'\n  }\n  // permission: {\n  //   addRole: '新增角色',\n  //   editPermission: '编辑权限',\n  //   roles: '你的权限',\n  //   switchRoles: '切换权限',\n  //   tips:\n  //     '在某些情况下，不适合使用 v-permission。例如：Element-UI 的 el-tab 或 el-table-column 以及其它动态渲染 dom 的场景。你只能通过手动设置 v-if 来实现。',\n  //   delete: '删除',\n  //   confirm: '确定',\n  //   cancel: '取消'\n  // },\n  // guide: {\n  //   description: '引导页对于一些第一次进入项目的人很有用，你可以简单介绍下项目的功能。本 Demo 是基于',\n  //   button: '打开引导'\n  // },\n  // components: {\n  //   documentation: '文档',\n  //   tinymceTips:\n  //     '富文本是管理后台一个核心的功能，但同时又是一个有很多坑的地方。在选择富文本的过程中我也走了不少的弯路，市面上常见的富文本都基本用过了，最终权衡了一下选择了Tinymce。更详细的富文本比较和介绍见',\n  //   dropzoneTips:\n  //     '由于我司业务有特殊需求，而且要传七牛 所以没用第三方，选择了自己封装。代码非常的简单，具体代码你可以在这里看到 @/components/Dropzone',\n  //   stickyTips: '当页面滚动到预设的位置会吸附在顶部',\n  //   backToTopTips1: '页面滚动到指定位置会在右下角出现返回顶部按钮',\n  //   backToTopTips2:\n  //     '可自定义按钮的样式、show/hide、出现的高度、返回的位置 如需文字提示，可在外部使用Element的el-tooltip元素',\n  //   imageUploadTips:\n  //     '由于我在使用时它只有vue@1版本，而且和mockjs不兼容，所以自己改造了一下，如果大家要使用的话，优先还是使用官方版本。'\n  // },\n  // table: {\n  //   dynamicTips1: '固定表头, 按照表头顺序排序',\n  //   dynamicTips2: '不固定表头, 按照点击顺序排序',\n  //   dragTips1: '默认顺序',\n  //   dragTips2: '拖拽后顺序',\n  //   title: '标题',\n  //   importance: '重要性',\n  //   type: '类型',\n  //   remark: '点评',\n  //   search: '搜索',\n  //   add: '添加',\n  //   export: '导出',\n  //   reviewer: '审核人',\n  //   id: '序号',\n  //   date: '时间',\n  //   author: '作者',\n  //   readings: '阅读数',\n  //   status: '状态',\n  //   actions: '操作',\n  //   edit: '编辑',\n  //   publish: '发布',\n  //   draft: '草稿',\n  //   delete: '删除',\n  //   cancel: '取 消',\n  //   confirm: '确 定'\n  // },\n  // example: {\n  //   warning:\n  //     '创建和编辑页面是不能被 keep-alive 缓存的，因为keep-alive 的 include 目前不支持根据路由来缓存，所以目前都是基于 component name 来进行缓存的。如果你想类似的实现缓存效果，可以使用 localStorage 等浏览器缓存方案。或者不要使用 keep-alive 的 include，直接缓存所有页面。详情见'\n  // },\n  // errorLog: {\n  //   tips: '请点击右上角bug小图标',\n  //   description:\n  //     '现在的管理后台基本都是spa的形式了，它增强了用户体验，但同时也会增加页面出问题的可能性，可能一个小小的疏忽就导致整个页面的死锁。好在 Vue 官网提供了一个方法来捕获处理异常，你可以在其中进行错误处理或者异常上报。',\n  //   documentation: '文档介绍'\n  // },\n  // excel: {\n  //   export: '导出',\n  //   selectedExport: '导出已选择项',\n  //   placeholder: '请输入文件名(默认excel-list)'\n  // },\n  // zip: {\n  //   export: '导出',\n  //   placeholder: '请输入文件名(默认file)'\n  // },\n  // pdf: {\n  //   tips: '这里使用   window.print() 来实现下载pdf的功能'\n  // },\n  // theme: {\n  //   change: '换肤',\n  //   documentation: '换肤文档',\n  //   tips: 'Tips: 它区别于 navbar 上的 theme-pick, 是两种不同的换肤方法，各自有不同的应用场景，具体请参考文档。'\n  // },\n  // tagsView: {\n  //   refresh: '刷新',\n  //   close: '关闭',\n  //   closeOthers: '关闭其它',\n  //   closeAll: '关闭所有'\n  // },\n  // settings: {\n  //   title: '系统布局配置',\n  //   theme: '主题色',\n  //   tagsView: '开启 Tags-View',\n  //   fixedHeader: '固定 Header',\n  //   sidebarLogo: '侧边栏 Logo'\n  // }\n}\n"
  },
  {
    "path": "src/layout/app-main/Breadcrumb.vue",
    "content": "<template>\n  <el-breadcrumb class=\"app-breadcrumb\" separator=\"/\">\n    <!--  mainNeedAnimation：控制该面包屑是否需要动画  -->\n    <transition-group v-if=\"settings.mainNeedAnimation\" name=\"breadcrumb\">\n      <!--  根据过滤后的数组生成面包屑  -->\n      <el-breadcrumb-item v-for=\"(item, index) in levelList\" :key=\"item.path\">\n        <span v-if=\"item.redirect === 'noRedirect' || index === levelList.length - 1\" class=\"no-redirect\">\n          {{ langTitle(item.meta?.title) }}\n        </span>\n        <a v-else @click.prevent=\"handleLink(item)\">{{ langTitle(item.meta?.title) }}</a>\n      </el-breadcrumb-item>\n    </transition-group>\n    <!--no transition-->\n    <template v-else>\n      <el-breadcrumb-item v-for=\"(item, index) in levelList\" :key=\"item.path\">\n        <span v-if=\"item.redirect === 'noRedirect' || index === levelList.length - 1\" class=\"no-redirect\">\n          {{ langTitle(item.meta?.title) }}\n        </span>\n        <a v-else @click.prevent=\"handleLink(item)\">{{ langTitle(item.meta?.title) }}</a>\n      </el-breadcrumb-item>\n    </template>\n  </el-breadcrumb>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch } from 'vue'\nimport { compile } from 'path-to-regexp'\nimport { useRoute, useRouter } from 'vue-router'\nimport type { RouterTypes } from '~/basic'\nimport { useBasicStore } from '@/store/basic'\nimport { langTitle } from '@/hooks/use-common'\nconst levelList = ref()\nconst { settings } = useBasicStore()\nconst route = useRoute()\nconst getBreadcrumb = () => {\n  // only show routes with has  meta.title\n  let matched: RouterTypes = route.matched.filter((item) => item.meta?.title)\n  //如果首页Dashboard,如果没有，添加Dashboard路由到第一个路由\n  const isHasDashboard = matched[0]?.name?.toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()\n  if (!isHasDashboard) {\n    matched = [{ path: '/dashboard', meta: { title: 'Dashboard' } }].concat(matched)\n  }\n  //过滤面包屑显示的数组\n  levelList.value = matched.filter((item) => item.meta && item.meta.title && item.meta.breadcrumb !== false)\n}\n\n//页面跳转处理\n//compile函数将返回一个用于将参数转换为有效路径的函数：\n//const  toPath =  compile ( \"/user/:id\" ,  {  encode : encodeURIComponent  } ) ;\n//toPath ( {  id : 123  } ) ; //=> \"/user/123\"\nconst pathCompile = (path) => {\n  const { params } = route\n  const toPath = compile(path)\n  return toPath(params)\n}\nconst router = useRouter()\n//如果有redirect地址直接跳转，没有跳转path\nconst handleLink = (item) => {\n  const { redirect, path } = item\n  if (redirect) {\n    router.push(redirect)\n    return\n  }\n  if (path) router.push(pathCompile(path))\n}\n//监听路由路径刷新 面包屑显示数组\nwatch(\n  () => route.path,\n  () => getBreadcrumb(),\n  { immediate: true }\n)\n</script>\n\n<style lang=\"scss\" scoped>\n.app-breadcrumb.el-breadcrumb {\n  display: inline-block;\n  font-size: 14px;\n  line-height: 50px;\n  margin-left: 8px;\n\n  .no-redirect {\n    color: var(--breadcrumb-no-redirect);\n    cursor: text;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/layout/app-main/Hamburger.vue",
    "content": "<template>\n  <div style=\"padding: 0 12px\" @click=\"toggleClick\">\n    <svg-icon icon-class=\"hamburger\" :class=\"{ 'is-active': isActive }\" class=\"hamburger-style\" />\n  </div>\n</template>\n\n<script setup lang=\"ts\">\nimport SvgIcon from '@/icons/SvgIcon.vue'\ndefineProps({\n  isActive: {\n    type: Boolean,\n    default: false\n  }\n})\nconst emit = defineEmits(['toggleClick'])\n//切换左侧栏关闭和隐藏\nconst toggleClick = () => {\n  emit('toggleClick')\n}\n</script>\n\n<style scoped lang=\"scss\">\n.hamburger-style {\n  color: var(--hamburger-color);\n  width: var(--hamburger-width);\n  height: var(--hamburger-height);\n  cursor: pointer;\n}\n\n.hamburger-style.is-active {\n  transform: rotate(180deg);\n}\n</style>\n"
  },
  {
    "path": "src/layout/app-main/Navbar.vue",
    "content": "<template>\n  <div class=\"navbar rowBC reset-el-dropdown\">\n    <div class=\"rowSC\">\n      <!--  切换sidebar按钮  -->\n      <hamburger\n        v-if=\"settings.showHamburger\"\n        :is-active=\"sidebar.opened\"\n        class=\"hamburger-container\"\n        @toggleClick=\"toggleSideBar\"\n      />\n      <!--  面包屑导航  -->\n      <breadcrumb class=\"breadcrumb-container\" />\n    </div>\n    <!--导航标题-->\n    <div v-if=\"settings.showNavbarTitle\" class=\"heardCenterTitle\">{{ settings.title }}</div>\n    <!-- 下拉操作菜单 -->\n    <div v-if=\"settings.ShowDropDown\" class=\"right-menu rowSC\">\n      <ScreenFull />\n      <ScreenLock/>\n      <ThemeSelect />\n      <SizeSelect />\n      <LangSelect />\n      <el-dropdown trigger=\"click\" size=\"medium\">\n        <div class=\"avatar-wrapper\">\n          <img src=\"https://github.jzfai.top/file/images/nav-right-logo.gif\" class=\"user-avatar\" />\n          <CaretBottom style=\"width: 1em; height: 1em; margin-left: 4px\" />\n        </div>\n        <template #dropdown>\n          <el-dropdown-menu>\n            <router-link to=\"/\">\n              <el-dropdown-item>{{ langTitle('Home') }}</el-dropdown-item>\n            </router-link>\n            <a target=\"_blank\" href=\"https://github.com/jzfai/vue3-admin-plus\">\n              <el-dropdown-item>{{ langTitle('Github') }}</el-dropdown-item>\n            </a>\n            <a target=\"_blank\" href=\"https://github.jzfai.top/low-code-platform\">\n              <el-dropdown-item>{{ langTitle('low-code-platform') }}</el-dropdown-item>\n            </a>\n            <a target=\"_blank\" href=\"https://github.jzfai.top/vue3-admin-doc\">\n              <el-dropdown-item>{{ langTitle('office-doc') }}</el-dropdown-item>\n            </a>\n            <!--<el-dropdown-item>修改密码</el-dropdown-item>-->\n            <el-dropdown-item divided @click=\"loginOut\">{{ langTitle('login out') }}</el-dropdown-item>\n          </el-dropdown-menu>\n        </template>\n      </el-dropdown>\n    </div>\n\n  </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { nextTick } from 'vue'\nimport { CaretBottom } from '@element-plus/icons-vue'\nimport { useRoute, useRouter } from 'vue-router'\nimport Breadcrumb from './Breadcrumb.vue'\nimport Hamburger from './Hamburger.vue'\nimport LangSelect from './component/LangSelect.vue'\nimport ScreenFull from './component/ScreenFull.vue'\nimport SizeSelect from './component/SizeSelect.vue'\nimport ThemeSelect from './component/ThemeSelect.vue'\nimport ScreenLock from './component/ScreenLock.vue'\nimport { resetState } from '@/hooks/use-permission'\nimport { elMessage } from '@/hooks/use-element'\nimport { useBasicStore } from '@/store/basic'\nimport { langTitle } from '@/hooks/use-common'\n\nconst basicStore = useBasicStore()\nconst { settings, sidebar, setToggleSideBar } = basicStore\nconst toggleSideBar = () => {\n  setToggleSideBar()\n}\n//退出登录\nconst router = useRouter()\nconst route = useRoute()\nconst loginOut = () => {\n  elMessage('退出登录成功')\n  router.push(`/login?redirect=${route.path}`)\n  nextTick(() => {\n    resetState()\n  })\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.navbar {\n  height: var(--nav-bar-height);\n  overflow: hidden;\n  position: relative;\n  background: var(--nav-bar-background);\n  box-shadow: var(--nav-bar-box-shadow);\n  z-index: 0;\n}\n\n//logo\n.avatar-wrapper {\n  margin-top: 5px;\n  position: relative;\n  cursor: pointer;\n\n  .user-avatar {\n    cursor: pointer;\n    width: 40px;\n    height: 40px;\n    border-radius: 10px;\n  }\n\n  .el-icon-caret-bottom {\n    cursor: pointer;\n    position: absolute;\n    right: -20px;\n    top: 25px;\n    font-size: 12px;\n  }\n}\n\n//center-title\n.heardCenterTitle {\n  text-align: center;\n  position: absolute;\n  top: 50%;\n  left: 46%;\n  font-weight: 600;\n  font-size: 20px;\n  transform: translate(-50%, -50%);\n}\n\n//drop-down\n.right-menu {\n  cursor: pointer;\n  margin-right: 40px;\n  background-color: var(--nav-bar-right-menu-background);\n}\n</style>\n"
  },
  {
    "path": "src/layout/app-main/TagsView.vue",
    "content": "<template>\n  <div id=\"tags-view-container\" class=\"tags-view-container\">\n    <div class=\"tags-view-wrapper\">\n      <router-link\n          v-for=\"tag in visitedViews\"\n          ref=\"refTag\"\n          :key=\"tag.path\"\n          v-slot=\"{ navigate }\"\n          :to=\"{ path: tag.path, query: tag.query, fullPath: tag.fullPath }\"\n          custom\n      >\n        <div\n            class=\"tags-view-item\"\n            :class=\"isActive(tag) ? 'active' : ''\"\n            @click.middle=\"!isAffix(tag) ? closeSelectedTag(tag) : ''\"\n            @contextmenu.prevent=\"openMenu(tag, $event)\"\n            @click=\"navigate\"\n        >\n          {{ langTitle(tag.title) }}\n          <Close v-if=\"!isAffix(tag)\" class=\"el-icon-close\" @click.prevent.stop=\"closeSelectedTag(tag)\" />\n        </div>\n      </router-link>\n    </div>\n    <div style=\"position:relative;top:-6px\">\n      <div v-show=\"visible\" class=\"triangle\" :style=\"{left: left + 'px'}\"/>\n      <ul v-show=\"visible\" :style=\"{ left: left + 'px', top: top + 'px' }\" class=\"contextmenu\">\n\n        <li @click=\"refreshSelectedTag(selectedTag)\">{{ langTitle('Refresh') }}</li>\n        <li v-if=\"!isAffix(selectedTag)\" @click=\"closeSelectedTag(selectedTag)\">{{ langTitle('Close') }}</li>\n        <li @click=\"closeOthersTags\">{{ langTitle('Close Others') }}</li>\n        <li @click=\"closeAllTags(selectedTag)\">{{ langTitle('Close All') }}</li>\n      </ul>\n    </div>\n\n  </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { getCurrentInstance, nextTick, onMounted, reactive, toRefs, watch } from 'vue'\nimport { Close } from '@element-plus/icons-vue'\nimport { resolve } from 'path-browserify'\nimport { useRoute, useRouter } from 'vue-router'\nimport { storeToRefs } from 'pinia/dist/pinia'\nimport type { RouterTypes } from '~/basic'\nimport { useBasicStore } from '@/store/basic'\nimport { useTagsViewStore } from '@/store/tags-view'\nimport { langTitle } from '@/hooks/use-common'\nconst route = useRoute()\nconst router = useRouter()\nconst state = reactive({\n  visible: false,\n  top: 0,\n  left: 0,\n  selectedTag: {},\n  affixTags: [] as RouterTypes\n})\n\nconst { visitedViews } = storeToRefs(useTagsViewStore())\n\nwatch(\n    () => route.path,\n    () => {\n      addTags()\n    }\n)\n\nwatch(\n    () => state.visible,\n    (value) => {\n      if (value) {\n        document.body.addEventListener('click', closeMenu)\n      } else {\n        document.body.removeEventListener('click', closeMenu)\n      }\n    }\n)\nonMounted(() => {\n  initTags()\n  addTags()\n})\n\n//判断当前点击的item项，是不是当前显示的路由项，如果是则高亮\nconst isActive = (param) => {\n  return route.path === param.path\n}\n//当路由设置meta.affix=true,关闭按钮消失\nconst isAffix = (tag) => {\n  return tag.meta && tag.meta.affix\n}\n\nconst filterAffixTags = (routes, basePath = '/') => {\n  let tags: RouterTypes = []\n  routes.forEach((route) => {\n    if (route.meta && route.meta.affix) {\n      const tagPath = resolve(basePath, route.path)\n      tags.push({\n        fullPath: tagPath,\n        path: tagPath,\n        name: route.name,\n        meta: { ...route.meta }\n      })\n    }\n    if (route.children) {\n      const tempTags = filterAffixTags(route.children, route.path)\n      if (tempTags.length >= 1) {\n        tags = [...tags, ...tempTags]\n      }\n    }\n  })\n  return tags\n}\n\n//初始\nconst tagsViewStore = useTagsViewStore()\nconst { allRoutes } = useBasicStore()\nconst initTags = () => {\n  //过滤affix=true的tags数组并赋值给state.affixTags，挂载到页面上\n  const affixTags = (state.affixTags = filterAffixTags(allRoutes))\n  for (const tag of affixTags) {\n    // Must have tag name\n    if (tag.name) {\n      tagsViewStore.addVisitedView(tag)\n    }\n  }\n}\nconst addTags = () => {\n  if (route?.name) {\n    tagsViewStore.addVisitedView(route)\n  }\n  return false\n}\n\n/*右键菜单部分*/\nconst vm = getCurrentInstance()?.proxy\n//右键打开菜单\nconst openMenu = (tag, e) => {\n  const menuMinWidth = 105\n  const offsetLeft = vm?.$el.getBoundingClientRect().left // container margin left\n  const offsetWidth = vm?.$el.offsetWidth // container width\n  const maxLeft = offsetWidth - menuMinWidth // left boundary\n  const left = e.clientX - offsetLeft + 15 // 15: margin right\n\n  if (left > maxLeft) {\n    state.left = maxLeft\n  } else {\n    state.left = left\n  }\n  state.top =16\n  state.visible = true\n  state.selectedTag = tag\n}\n\nconst basicStore = useBasicStore()\n\n//关闭当前标签\nconst closeSelectedTag = (view) => {\n  tagsViewStore.delVisitedView(view).then((visitedViews) => {\n    if (isActive(view)) {\n      toLastView(visitedViews, view)\n    }\n    //remove keep-alive by the closeTabRmCache\n    if (view.meta?.closeTabRmCache) {\n      const routerLevel = view.matched.length\n      if (routerLevel === 2) {\n        basicStore.delCachedView(view.name)\n      }\n      if (routerLevel === 3) {\n        basicStore.delCacheViewDeep(view.name)\n      }\n    }\n  })\n}\n\n//刷新标签\nconst refreshSelectedTag = (view) => {\n  const { fullPath } = view\n  nextTick(() => {\n    router.replace({\n      path: `/redirect${fullPath}`\n    })\n  })\n}\n\n//右键关闭菜单\nconst closeMenu = () => {\n  state.visible = false\n}\n//关闭其他标签\nconst closeOthersTags = () => {\n  router.push(state.selectedTag)\n  tagsViewStore.delOthersVisitedViews(state.selectedTag)\n}\n//关闭所有标签\nconst closeAllTags = (view) => {\n  tagsViewStore.delAllVisitedViews().then((visitedViews) => {\n    if (state.affixTags.some((tag) => tag.path === view.path)) {\n      return\n    }\n    toLastView(visitedViews, view)\n  })\n}\n//跳转最后一个标签\nconst toLastView = (visitedViews, view) => {\n  //visitedViews.at(-1)获取数组最后一个元素\n  const latestView = visitedViews.at(-1)\n  if (latestView) {\n    router.push(latestView.fullPath)\n  } else {\n    if (view.name === 'Dashboard') {\n      // to reload home page\n      router.replace({ path: `/redirect${view.fullPath}` })\n    } else {\n      router.push('/')\n    }\n  }\n}\n\n//export to page use\nconst { visible, top, left, selectedTag } = toRefs(state)\n</script>\n\n<style lang=\"scss\" scoped>\n//三角形汽包\n.triangle {\n  position: relative;\n  width: 0;\n  height: 0;\n  left: 10px;\n  z-index: 100;\n  border: 8px solid transparent;\n  border-bottom-color: #eee;\n  opacity:0.4;\n}\n.tags-view-container {\n  height: var(--tag-view-height);\n  width: 100%;\n  position: relative;\n  background: var(--tags-view-background);\n  border-bottom: 1px solid var(--tags-view-border-bottom);\n  box-shadow: var(--tags-view-box-shadow);\n  .tags-view-wrapper {\n    .tags-view-item {\n      display: inline-block;\n      position: relative;\n      cursor: pointer;\n      height: 27px;\n      line-height: 26px;\n      border: 1px solid var(--tags-view-item-border-color);\n      color: var(--tags-view-item-color);\n      background: var(--tags-view-item-background);\n      padding: 0 8px;\n      font-size: 12px;\n      margin-left: 5px;\n      margin-top: 3px;\n      &:first-of-type {\n        margin-left: 10px;\n      }\n      &:last-of-type {\n        margin-right: 15px;\n      }\n      &.active {\n        background-color: var(--tags-view-item-active-background);\n        color: var(--tags-view-item-active-color);\n        border-color: var(--tags-view-item-active-border-color);\n        &::before {\n          content: '';\n          background: var(--tags-view-background);\n          display: inline-block;\n          width: 8px;\n          height: 8px;\n          border-radius: 50%;\n          position: relative;\n          margin-right: 2px;\n        }\n      }\n    }\n  }\n  .contextmenu {\n    z-index: 100;\n    margin: 0;\n    background: var(--tags-view-contextmenu-background);\n    position: absolute;\n    list-style-type: none;\n    padding: 5px 0;\n    border-radius: 4px;\n    font-size: 12px;\n    font-weight: 400;\n    color: var(--tags-view-contextmenu-color);\n    box-shadow: var(--tags-view-contextmenu-box-shadow);\n    li {\n      margin: 0;\n      padding: 7px 16px;\n      cursor: pointer;\n      &:hover {\n        background: var(--tags-view-contextmenu-hover-background);\n      }\n    }\n  }\n}\n</style>\n\n<style lang=\"scss\">\n\n\n//reset element css of el-icon-close\n.tags-view-wrapper {\n  .tags-view-item {\n    border-radius: 3px;\n    .el-icon-close {\n      border-radius: 6px;\n      width: 12px;\n      height: 12px;\n      transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);\n      transform-origin: 100% 50%;\n      vertical-align: -2px;\n\n      &:hover {\n        background-color: var(--tags-view-close-icon-hover-background);\n        color: var(--tags-view-close-icon-hover-color);\n      }\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "src/layout/app-main/component/LangSelect.vue",
    "content": "<template>\n  <el-dropdown trigger=\"click\" type=\"primary\" @command=\"handleSetLang\">\n    <svg-icon icon-class=\"language\" style=\"width: 20px; height: 20px\" class=\"mr-20px\" />\n    <template #dropdown>\n      <el-dropdown-menu>\n        <el-dropdown-item\n          v-for=\"item in langOptions\"\n          :key=\"item.value\"\n          :command=\"item.value\"\n          :disabled=\"language === item.value\"\n        >\n          <h3 class=\"pt-10px pb-10px font-langPx14\">{{ item.label }}</h3>\n        </el-dropdown-item>\n      </el-dropdown-menu>\n    </template>\n  </el-dropdown>\n</template>\n\n<script setup lang=\"ts\">\nimport { reactive, toRefs } from 'vue'\nimport { storeToRefs } from 'pinia/dist/pinia'\nimport { useRoute } from 'vue-router'\nimport SvgIcon from '@/icons/SvgIcon.vue'\nimport { useConfigStore } from '@/store/config'\nconst state = reactive({\n  langOptions: [\n    { label: '中文', value: 'zh' },\n    { label: 'English', value: 'en' }\n  ]\n})\nconst configStore = useConfigStore()\nconst { language } = storeToRefs(configStore)\nconst route = useRoute()\nconst handleSetLang = (lang) => {\n  //refresh i18n\n  configStore.setLanguage(lang, route.meta?.title)\n}\nconst { langOptions } = toRefs(state)\n</script>\n\n<style scoped lang=\"scss\"></style>\n"
  },
  {
    "path": "src/layout/app-main/component/ScreenFull.vue",
    "content": "<template>\n  <svg-icon\n    :icon-class=\"isFullscreen ? 'exit-fullscreen' : 'fullscreen'\"\n    style=\"width: 17px; height: 17px\"\n    class=\"mr-12px\"\n    @click=\"toggleScreen\"\n  />\n</template>\n\n<script setup lang=\"ts\">\n//@ts-ignore\nimport { onMounted, onUnmounted, reactive, toRefs } from 'vue'\nimport screenfull from 'screenfull'\nimport { ElMessage } from 'element-plus'\nimport SvgIcon from '@/icons/SvgIcon.vue'\nconst state = reactive({\n  isFullscreen: false\n})\nonMounted(() => {\n  init()\n})\nonUnmounted(() => {\n  destroy()\n})\nconst toggleScreen = () => {\n  if (!screenfull.isEnabled) {\n    ElMessage({\n      message: 'you browser can not work',\n      type: 'warning'\n    })\n    return false\n  }\n  screenfull.toggle()\n}\nconst change = () => {\n  state.isFullscreen = screenfull.isFullscreen\n}\nconst init = () => {\n  if (screenfull.isEnabled) {\n    screenfull.on('change', change)\n  }\n}\nconst destroy = () => {\n  if (screenfull.isEnabled) {\n    screenfull.off('change', change)\n  }\n}\nconst { isFullscreen } = toRefs(state)\n</script>\n\n<style lang=\"scss\" scoped>\n.nav-svg-icon {\n  font-size: 18px;\n  color: #5a5e66;\n  margin-top: 4px;\n}\n</style>\n"
  },
  {
    "path": "src/layout/app-main/component/ScreenLock.vue",
    "content": "<template>\n  <svg-icon icon-class=\"lock\" style=\"width: 18px; height: 19px\" class=\"mr-12px\" @click=\"open = true\" />\n  <Teleport to=\"body\">\n    <transition enter-active-class=\"screen-locker-lock\" append-to-body leave-active-class=\"screen-locker-unlock\">\n      <div v-if=\"open\" class=\"screen-locker\">\n        <div class=\"screen-avatar\">\n          <el-avatar round :size=\"128\" src=\"https://github.jzfai.top/file/images/nav-right-logo.gif\" />\n          <div class=\"screen-nickname\">Vue3 Admin Plus</div>\n        </div>\n        <div ref=\"slider\" class=\"screen-slider\">\n          <div class=\"screen-locker-placeholder\">滑动解锁</div>\n          <div ref=\"sliderButton\" class=\"screen-slider-button\" @mousedown=\"onMousedown\">\n            <el-icon :size=\"25\">\n              <icon />\n            </el-icon>\n          </div>\n        </div>\n      </div>\n    </transition>\n  </Teleport>\n</template>\n<script setup>\nimport { computed, ref, watch } from 'vue'\nimport { ArrowRightBold, Unlock } from '@element-plus/icons-vue'\nimport SvgIcon from '@/icons/SvgIcon.vue'\nconst open = ref(false)\nconst slider = ref(null)\nconst sliderButton = ref(null)\nlet startX = 0\nlet distance = 0\nlet maxDistance = 0\nlet minDistance = 0\nconst isTrigger = ref(false)\n\nconst onMousedown = (e) => {\n  distance = 0\n  maxDistance = 0\n  minDistance = 0\n  isTrigger.value = false\n\n  sliderButton.value.style.transition = ''\n  startX = e.screenX\n  maxDistance = slider.value.clientWidth - sliderButton.value.clientWidth - 10\n  document.addEventListener('mousemove', onMousemove)\n  document.addEventListener('mouseup', onMouseup)\n}\n\nconst onMousemove = (e) => {\n  distance = e.screenX - startX\n  if (isTrigger.value) {\n    distance = maxDistance\n  }\n  if (distance <= minDistance) {\n    distance = minDistance\n  }\n  if (distance >= maxDistance) {\n    distance = maxDistance\n    if (!isTrigger.value) {\n      isTrigger.value = true\n      setTimeout(() => {\n        open.value = false\n      }, 300)\n    }\n  }\n  if (open.value) {\n    sliderButton.value.style.transform = `translateX(${distance}px)`\n  }\n}\n\nconst onMouseup = () => {\n  document.removeEventListener('mousemove', onMousemove)\n  document.removeEventListener('mouseup', onMouseup)\n\n  if (!isTrigger.value) {\n    // 恢复原始状态\n    distance = 0\n    maxDistance = 0\n    minDistance = 0\n    isTrigger.value = false\n\n    if (open.value) {\n      sliderButton.value.style.transition = 'all 0.4s'\n      sliderButton.value.style.transform = `translateX(${distance}px)`\n    }\n  }\n}\nwatch(\n  () => open.value,\n  () => {\n    if (open.value) {\n      isTrigger.value = false\n    }\n  }\n)\nconst icon = computed(() => {\n  return isTrigger.value ? Unlock : ArrowRightBold\n})\n</script>\n\n<style scoped lang=\"scss\">\n.screen-locker {\n  position: fixed;\n  left: 0;\n  right: 0;\n  top: 0;\n  bottom: 0;\n  z-index: 100;\n  background-color: rgba(0, 0, 0, 0.3);\n  /* backdrop-filter暂不兼容firefox */\n  backdrop-filter: blur(10px);\n  box-shadow: 0 0 20px 5px #0000000f;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  flex-direction: column;\n}\n\n.screen-locker-lock {\n  animation: lock-down 1s ease-in-out;\n}\n\n.screen-locker-unlock {\n  animation: lock-up 1s ease-in-out;\n}\n\n@keyframes lock-down {\n  0% {\n    transform: translate3d(0, -100%, 0);\n  }\n  60% {\n    transform: translate3d(0, 25px, 0);\n  }\n  75% {\n    transform: translate3d(0px, 0, 0);\n  }\n  90% {\n    transform: translate3d(0px, 0, 0);\n  }\n  100% {\n    transform: none;\n  }\n}\n\n@keyframes lock-up {\n  0% {\n    transform: translate3d(0, 0px, 0);\n  }\n  90% {\n    transform: translate3d(0px, -100%, 0);\n  }\n  100% {\n    transform: none;\n    opacity: 0;\n  }\n}\n\n.screen-avatar {\n  margin-bottom: 50px;\n  display: flex;\n  justify-content: center;\n  flex-direction: column;\n  align-items: center;\n}\n\n.screen-nickname {\n  font-size: 30px;\n  font-weight: 400;\n  margin-top: 10px;\n}\n\n.screen-slider {\n  width: 300px;\n  height: 60px;\n  border-radius: 100px;\n  background-image: linear-gradient(to right, rgb(72 168 237 / 25%), rgba(255, 255, 255, 0.4), rgb(72 168 237 / 25%));\n  /* 背景渐变色大小 */\n  background-size: 200%;\n  animation: sun 7s infinite;\n  position: relative;\n  box-shadow: 0 0 20px 2px rgba(0, 0, 0, 0.15);\n}\n\n.screen-slider:before {\n  content: '';\n  position: absolute;\n  top: -6px;\n  bottom: -6px;\n  left: -6px;\n  right: -6px;\n  border-radius: 60px;\n  background-image: linear-gradient(to right, rgb(72 168 237 / 25%), rgba(255, 255, 255, 0.4), rgb(72 168 237 / 25%));\n  background-size: 200%;\n  /* 设置模糊度 显示发光效果 */\n  filter: blur(10px);\n  opacity: 0.5;\n  animation: sun 7s infinite;\n}\n\n.screen-slider-button {\n  width: 50px;\n  height: 50px;\n  margin: 5px;\n  border-radius: 50%;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.15);\n  backdrop-filter: blur(10px);\n}\n\n.screen-locker-placeholder {\n  position: absolute;\n  left: 50%;\n  top: 50%;\n  transform: translate3d(-50%, -50%, 0);\n  pointer-events: none;\n  opacity: 0.5;\n  user-select: none;\n}\n\n@keyframes sun {\n  100% {\n    background-position: -400% 0;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/layout/app-main/component/SizeSelect.vue",
    "content": "<template>\n  <el-dropdown id=\"size-select\" trigger=\"click\" type=\"primary\" @command=\"handleSetSize\">\n    <svg-icon icon-class=\"size\" style=\"width: 18px; height: 18px\" class=\"mr-12px\" />\n    <template #dropdown>\n      <el-dropdown-menu>\n        <el-dropdown-item\n          v-for=\"item in sizeOptions\"\n          :key=\"item.value\"\n          :command=\"item.value\"\n          :disabled=\"size === item.value\"\n        >\n          <h3 class=\"pt-10px pb-10px font-sizePx14\">{{ item.label }}</h3>\n        </el-dropdown-item>\n      </el-dropdown-menu>\n    </template>\n  </el-dropdown>\n</template>\n\n<script setup lang=\"ts\">\nimport { reactive, toRefs } from 'vue'\nimport { storeToRefs } from 'pinia/dist/pinia'\nimport SvgIcon from '@/icons/SvgIcon.vue'\nimport { useConfigStore } from '@/store/config'\nconst state = reactive({\n  sizeOptions: [\n    { label: 'Large ', value: 'large' },\n    { label: 'Default ', value: 'default' },\n    { label: 'Small', value: 'small' }\n  ]\n})\nconst configStore = useConfigStore()\nconst { size } = storeToRefs(configStore)\nconst handleSetSize = (size) => {\n  configStore.setSize(size)\n}\nconst { sizeOptions } = toRefs(state)\n</script>\n\n<style scoped lang=\"scss\"></style>\n"
  },
  {
    "path": "src/layout/app-main/component/ThemeSelect.vue",
    "content": "<template>\n  <el-dropdown trigger=\"click\" type=\"primary\" @command=\"handleSetTheme\">\n    <svg-icon icon-class=\"theme-icon\" style=\"width: 22px; height: 23px\" class=\"mr-12px\" />\n    <template #dropdown>\n      <el-dropdown-menu>\n        <el-dropdown-item\n          v-for=\"item in themeOptions\"\n          :key=\"item.value\"\n          :command=\"item.value\"\n          :disabled=\"theme === item.value\"\n        >\n          <h3 class=\"pt-6px pb-10px text-16px\">{{ item.label }}</h3>\n        </el-dropdown-item>\n      </el-dropdown-menu>\n    </template>\n  </el-dropdown>\n</template>\n\n<script setup lang=\"ts\">\nimport { reactive, toRefs } from 'vue'\nimport { storeToRefs } from 'pinia/dist/pinia'\nimport SvgIcon from '@/icons/SvgIcon.vue'\nimport { useConfigStore } from '@/store/config'\nconst configStore = useConfigStore()\n\nconst { theme } = storeToRefs(configStore)\nconst state = reactive({\n  themeOptions: [\n    { label: 'base', value: 'base-theme' },\n    { label: 'dark', value: 'dark' },\n    { label: 'lighting', value: 'lighting-theme' },\n    { label: 'china-red', value: 'china-red' }\n  ]\n})\nconst handleSetTheme = (theme) => {\n  configStore.setTheme(theme)\n}\nconst { themeOptions } = toRefs(state)\n</script>\n\n<style scoped lang=\"scss\">\n.theme-icon-style {\n  height: 23px;\n  width: 23px;\n  margin-left: 8px;\n  margin-right: 8px;\n  color: #494949; //#ff9901;\n  position: relative;\n  font-weight: bold;\n  top: 1px;\n}\n</style>\n"
  },
  {
    "path": "src/layout/app-main/index.vue",
    "content": "<template>\n  <div class=\"app-main\" :class=\"{ 'show-tag-view': settings.showTagsView }\">\n    <router-view v-slot=\"{ Component }\">\n      <!--has transition  setting by settings.mainNeedAnimation-->\n      <transition v-if=\"settings.mainNeedAnimation\" name=\"fade-transform\" mode=\"out-in\">\n        <keep-alive :include=\"cachedViews\">\n          <component :is=\"Component\" :key=\"key\" />\n        </keep-alive>\n      </transition>\n      <!-- no transition -->\n      <keep-alive v-else :include=\"cachedViews\">\n        <component :is=\"Component\" :key=\"key\" />\n      </keep-alive>\n    </router-view>\n  </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { storeToRefs } from 'pinia/dist/pinia'\nimport { useRoute } from 'vue-router'\nimport type { rawConfig } from '~/basic'\nimport { useBasicStore } from '@/store/basic'\nimport { cloneDeep } from '@/hooks/use-common'\nconst { settings, cachedViews } = storeToRefs(useBasicStore())\nconst route = useRoute()\nconst key = computed(() => route.path)\n/*listen the component name changing, then to keep-alive the page*/\n// cachePage: is true, keep-alive this Page\n// leaveRmCachePage: is true, keep-alive remote when page leave\nlet oldRoute: rawConfig = {}\n// let deepOldRouter: RouteLocationMatched | null = null\nlet cacheGroup: any = []\nconst basicStore = useBasicStore()\n// const removeDeepChildren = (deepOldRouter) => {\n//   deepOldRouter.children?.forEach((fItem) => {\n//     basicStore.delCacheViewDeep(fItem.name)\n//   })\n// }\nwatch(\n  () => route.name,\n  () => {\n    const routerLevel = route.matched.length\n\n    //缓存组处理\n    //first judge cacheGroup and then  remove\n    if (cacheGroup.length) {\n      if (!cacheGroup.includes(route.name)) {\n        cacheGroup.forEach((item) => {\n          basicStore.delCachedView(item)\n        })\n      }\n    }\n    //and then cache the current router config page\n    if (route.meta?.cacheGroup) {\n      cacheGroup = route.meta?.cacheGroup || []\n      cacheGroup.forEach((fItem) => {\n        basicStore.addCachedView(fItem)\n      })\n    }\n\n    //二级路由处理\n    if (routerLevel === 2) {\n      if (oldRoute?.name) {\n        if (oldRoute.meta?.leaveRmCachePage && oldRoute.meta?.cachePage) {\n          basicStore.delCachedView(oldRoute.name)\n        }\n      }\n      if (route.name) {\n        if (route.meta?.cachePage) {\n          basicStore.addCachedView(route.name)\n        }\n      }\n    }\n    //warning remove the third routerLevel cache func\n    //三级路由处理\n    // if (routerLevel === 3) {\n    //   //三级时存储当前路由对象的上一级\n    //   const parentRoute = route.matched[1]\n    //   //否则走正常两级路由处理流程\n    //   if (oldRoute?.name) {\n    //     if (oldRoute.meta?.leaveRmCachePage && oldRoute.meta?.cachePage) {\n    //       basicStore.delCacheViewDeep(oldRoute.name)\n    //     }\n    //   }\n    //\n    //   //取的是第二级的name\n    //   if (parentRoute.name && parentRoute.meta?.cachePage) {\n    //     deepOldRouter = parentRoute\n    //     basicStore.addCachedView(deepOldRouter.name)\n    //     if (route.name) {\n    //       if (route.meta?.cachePage) {\n    //         //和第三级的name进行缓存\n    //         basicStore.addCachedViewDeep(route.name)\n    //       }\n    //     }\n    //   }\n    // }\n    oldRoute = cloneDeep({ name: route.name, meta: route.meta })\n  },\n  { immediate: true }\n)\n</script>\n\n<style scoped lang=\"scss\">\n.app-main {\n  padding: var(--app-main-padding);\n  position: relative;\n  overflow: hidden;\n  background-color: var(--app-main-background);\n  min-height: calc(100vh - #{var(--nav-bar-height)}) !important;\n}\n.show-tag-view {\n  min-height: calc(100vh - #{var(--nav-bar-height)} - #{var(--tag-view-height)}) !important;\n}\n.fixed-header + .app-main {\n  padding-top: 50px;\n}\n</style>\n"
  },
  {
    "path": "src/layout/index.vue",
    "content": "<template>\n  <div :class=\"classObj\" class=\"layout-wrapper\">\n    <!--left side-->\n    <Sidebar v-if=\"settings.showLeftMenu\" class=\"sidebar-container\" />\n    <!--right container-->\n    <div class=\"main-container\">\n      <Navbar v-if=\"settings.showTopNavbar\" />\n      <TagsView v-if=\"settings.showTagsView\" />\n      <AppMain />\n    </div>\n  </div>\n</template>\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport Sidebar from './sidebar/index.vue'\nimport AppMain from './app-main/index.vue'\nimport Navbar from './app-main/Navbar.vue'\nimport TagsView from './app-main/TagsView.vue'\nimport { useBasicStore } from '@/store/basic'\nimport { resizeHandler } from '@/hooks/use-layout'\nconst { sidebar, settings } = useBasicStore()\nconst classObj = computed(() => {\n  return {\n    closeSidebar: !sidebar.opened,\n    hideSidebar: !settings.showLeftMenu\n  }\n})\nresizeHandler()\n</script>\n\n<style lang=\"scss\" scoped>\n.main-container {\n  min-height: 100%;\n  transition: margin-left var(--sideBar-switch-duration);\n  margin-left: var(--side-bar-width);\n  position: relative;\n}\n.sidebar-container {\n  transition: width var(--sideBar-switch-duration);\n  width: var(--side-bar-width) !important;\n  background-color: var(--el-menu-bg-color);\n  height: 100%;\n  position: fixed;\n  font-size: 0;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  overflow: hidden;\n  border-right: 0.5px solid var(--side-bar-border-right-color);\n}\n.closeSidebar {\n  .sidebar-container {\n    width: 54px !important;\n  }\n  .main-container {\n    margin-left: 54px !important;\n  }\n}\n.hideSidebar {\n  .sidebar-container {\n    width: 0 !important;\n  }\n  .main-container {\n    margin-left: 0;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/layout/sidebar/Link.vue",
    "content": "<template>\n  <component :is=\"type\" v-bind=\"linkProps(to)\">\n    <slot />\n  </component>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { isExternal } from '@/hooks/use-layout'\n\nconst props = defineProps({\n  to: { type: String, required: true }\n})\n//判断是否时外链，true: 使用 <a/>标签， false: <router-link/>\nconst type = computed(() => {\n  if (isExternal(props.to)) return 'a'\n  return 'router-link'\n})\n//判断是否时外链，true: 返回 <a/>标签跳转属性， false: 直接使用当前路径\nconst linkProps = (to) => {\n  if (isExternal(props.to)) {\n    return {\n      href: to,\n      target: '_blank',\n      //没有rel=“noopener noreferrer”的情况下使用target=“_blank”是有安全风险，超链接a标签的rel=\"noopener noreferrer\"属性是一种新特性，它能让网站更安全\n      rel: 'noopener'\n    }\n  }\n  return { to }\n}\n</script>\n"
  },
  {
    "path": "src/layout/sidebar/Logo.vue",
    "content": "<template>\n  <div class=\"sidebar-logo-container\" :class=\"{ collapse: collapse }\">\n    <transition name=\"sidebar-logo-fade\">\n      <!--  折叠显示   -->\n      <router-link v-if=\"collapse\" class=\"sidebar-logo-link\" to=\"/\">\n        <svg-icon v-if=\"logo\" :icon-class=\"logo\" class=\"sidebar-logo\" />\n        <h1 v-else class=\"sidebar-title\">{{ title }}</h1>\n      </router-link>\n      <!--  正常显示   -->\n      <router-link v-else class=\"sidebar-logo-link\" to=\"/\">\n        <svg-icon v-if=\"logo\" :icon-class=\"logo\" class=\"sidebar-logo\" />\n        <h1 class=\"sidebar-title\">{{ title }}</h1>\n      </router-link>\n    </transition>\n  </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { reactive, toRefs } from 'vue'\nimport { useBasicStore } from '@/store/basic'\nimport SvgIcon from '@/icons/SvgIcon.vue'\nconst { settings } = useBasicStore()\ndefineProps({\n  //是否折叠\n  collapse: {\n    type: Boolean,\n    required: true\n  }\n})\nconst state = reactive({\n  title: settings.title,\n  //src/icons/common/sidebar-logo.svg\n  logo: 'sidebar-logo'\n})\n//export to page for use\nconst { title, logo } = toRefs(state)\n</script>\n\n<style lang=\"scss\">\n//vue3.0 过度效果更改  enter-> enter-from   leave-> leave-from\n.sidebar-logo-container {\n  position: relative;\n  width: 100%;\n  height: 50px;\n  line-height: 50px;\n  background: var(--sidebar-logo-background);\n  padding-left: 14px;\n  text-align: left;\n  overflow: hidden;\n  & .sidebar-logo-link {\n    height: 100%;\n    width: 100%;\n    & .sidebar-logo {\n      fill: currentColor;\n      color: var(--sidebar-logo-color);\n      width: var(--sidebar-logo-width);\n      height: var(--sidebar-logo-height);\n      vertical-align: middle;\n      margin-right: 12px;\n    }\n    & .sidebar-title {\n      display: inline-block;\n      margin: 0;\n      color: var(--sidebar-logo-title-color);\n      font-weight: 600;\n      line-height: 50px;\n      font-size: 14px;\n      font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;\n      vertical-align: middle;\n    }\n  }\n  &.collapse {\n    .sidebar-logo {\n      margin-right: 0;\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "src/layout/sidebar/MenuIcon.vue",
    "content": "<template>\n  <!-- 如果有 elSvgIcon 显示 elSvgIcon 没有显示 icon-->\n  <el-icon v-if=\"meta?.elSvgIcon\" >\n    <component :is=\"meta.elSvgIcon\" />\n  </el-icon>\n  <div v-else-if=\"meta?.icon\"  class=\"menu-svg-class\"><svg-icon :icon-class=\"meta?.icon\"   /></div>\n</template>\n\n<script setup lang=\"ts\">\n// import * as ElSvg from '@element-plus/icons-vue'\ndefineProps({\n  meta: { type: Object, default: null }\n})\n</script>\n\n<style scoped lang=\"scss\">\n.menu-svg-class {\n  vertical-align: middle;\n  margin-left: 1px;\n  width: 29px;\n  padding-left: 5px;\n  text-align: left;\n}\n</style>\n"
  },
  {
    "path": "src/layout/sidebar/SidebarItem.vue",
    "content": "<template>\n  <template v-if=\"!item.hidden\">\n    <template v-if=\"showSidebarItem(item.children, item)\">\n      <Link v-if=\"onlyOneChild.meta\" :to=\"resolvePath(onlyOneChild.path)\">\n        <el-menu-item :index=\"resolvePath(onlyOneChild.path)\" :class=\"{ 'submenu-title-noDropdown': !isNest }\">\n          <MenuIcon :meta=\"onlyOneChild.meta || item.meta\" />\n          <template #title>{{ langTitle(onlyOneChild.meta?.title) }}</template>\n        </el-menu-item>\n      </Link>\n    </template>\n    <el-sub-menu v-else :index=\"resolvePath(item.path)\">\n      <template v-if=\"item.meta\" #title>\n        <MenuIcon :meta=\"item.meta\" />\n        <span>{{ langTitle(item.meta.title) }}</span>\n      </template>\n      <SidebarItem\n        v-for=\"child in item.children\"\n        :key=\"child.path\"\n        :is-nest=\"true\"\n        :item=\"child\"\n        :base-path=\"resolvePath(child.path)\"\n      />\n    </el-sub-menu>\n  </template>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { resolve } from 'path-browserify'\nimport Link from './Link.vue'\nimport MenuIcon from './MenuIcon.vue'\nimport type { RouteRawConfig } from '~/basic'\nimport { isExternal } from '@/hooks/use-layout'\nimport { langTitle } from '@/hooks/use-common'\n\nconst props = defineProps({\n  //每一个router Item\n  item: {\n    type: Object,\n    required: true\n  },\n  //用于判断是不是子Item,设置响应的样式\n  isNest: {\n    type: Boolean,\n    default: false\n  },\n  //基础路径，用于拼接\n  basePath: {\n    type: String,\n    default: ''\n  }\n})\n//显示sidebarItem 的情况\nconst onlyOneChild = ref()\nconst showSidebarItem = (children = [], parent) => {\n  const showingChildren = children.filter((item: RouteRawConfig) => {\n    if (item.hidden) {\n      return false\n    } else {\n      return true\n    }\n  })\n  if (showingChildren.length === 1 && !parent?.alwaysShow) {\n    onlyOneChild.value = showingChildren[0]\n    return true\n  }\n  if (showingChildren.length === 0) {\n    onlyOneChild.value = { ...parent, path: '', noChildren: true }\n    return true\n  }\n  return false\n}\nconst resolvePath = (routePath) => {\n  if (isExternal(routePath)) {\n    return routePath\n  }\n  if (isExternal(props.basePath)) {\n    return props.basePath\n  }\n  return resolve(props.basePath, routePath)\n}\n</script>\n"
  },
  {
    "path": "src/layout/sidebar/index.vue",
    "content": "<template>\n  <div id=\"Sidebar\" class=\"reset-menu-style\">\n    <!--logo-->\n    <Logo v-if=\"settings.sidebarLogo\" :collapse=\"!sidebar.opened\" />\n    <!--router menu-->\n    <el-scrollbar>\n      <el-menu\n        class=\"el-menu-vertical\"\n        :collapse=\"!sidebar.opened\"\n        :default-active=\"activeMenu\"\n        :collapse-transition=\"false\"\n        mode=\"vertical\"\n      >\n        <sidebar-item v-for=\"route in allRoutes\" :key=\"route.path\" :item=\"route\" :base-path=\"route.path\" />\n      </el-menu>\n    </el-scrollbar>\n  </div>\n</template>\n\n<script setup>\nimport { computed } from 'vue'\nimport { storeToRefs } from 'pinia/dist/pinia'\nimport { useRoute } from 'vue-router'\nimport Logo from './Logo.vue'\nimport SidebarItem from './SidebarItem.vue'\nimport { useBasicStore } from '@/store/basic'\nconst { settings, allRoutes, sidebar } = storeToRefs(useBasicStore())\nconst routeInstance = useRoute()\nconst activeMenu = computed(() => {\n  const { meta, path } = routeInstance\n  // if set path, the sidebar will highlight the path you set\n  if (meta.activeMenu) {\n    return meta.activeMenu\n  }\n  return path\n})\n</script>\n<style lang=\"scss\">\n//fix open the item style issue\n.el-menu-vertical {\n  width: var(--side-bar-width);\n}\n.reset-menu-style{\n  border-right: 1px solid var(--side-bar-border-right-color);\n}\n</style>\n"
  },
  {
    "path": "src/lib/el-svg-icon.ts",
    "content": "import * as components from '@element-plus/icons-vue'\n\nexport default {\n    install: (app) => {\n        for (const key in components) {\n            const componentConfig = components[key];\n            app.component(componentConfig.name, componentConfig);\n        }\n    },\n};\n"
  },
  {
    "path": "src/lib/element-plus.ts",
    "content": "import * as AllComponent from 'element-plus'\n//element-plus中按需引入会引起首次加载过慢\nconst elementPlusComponentNameArr = ['ElButton']\nexport default function (app) {\n  elementPlusComponentNameArr.forEach((component) => {\n    app.component(component, AllComponent[component])\n  })\n}\n"
  },
  {
    "path": "src/main.ts",
    "content": "import { createApp } from 'vue'\nimport { createPinia } from 'pinia'\nimport piniaPluginPersistedstate from 'pinia-plugin-persistedstate'\nimport ElementPlus from 'element-plus'\nimport App from './App.vue'\nimport router from './router'\n\n//import theme\nimport './theme/index.scss'\n\n//import unocss\nimport 'uno.css'\n\n//i18n\nimport { setupI18n } from '@/lang'\n\nimport '@/styles/index.scss' // global css\n\n//svg-icon\nimport 'virtual:svg-icons-register'\nimport svgIcon from '@/icons/SvgIcon.vue'\nimport directive from '@/directives'\n\n//import router intercept\nimport './permission'\n\n//import element-plus\nimport 'element-plus/dist/index.css'\n\n//import element-plus svg icon\nimport ElSvgIcon from \"@/lib/el-svg-icon\"\nconst app = createApp(App)\napp.use(ElSvgIcon)\n\n\n//router\napp.use(router)\n\n//pinia\nconst pinia = createPinia()\npinia.use(piniaPluginPersistedstate)\napp.use(pinia)\n\n//i18n\napp.use(setupI18n)\napp.component('SvgIcon', svgIcon)\ndirective(app)\n\n//element-plus\napp.use(ElementPlus)\n\napp.mount('#app')\n"
  },
  {
    "path": "src/mock-prod-server.ts",
    "content": "// vite-plugin-mock v3.0.1 版本 生产mock有问题\n// import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'\n// //https://cn.vitejs.dev/guide/features.html#glob-import\n// // @ts-ignore\n// const modulesFiles = import.meta.glob('../mock/*', { eager: true })\n// let modules = []\n// for (const filePath in modulesFiles) {\n//   //读取文件内容到 modules\n//   modules = modules.concat(modulesFiles[filePath].default)\n// }\n// export function setupProdMockServer() {\n//   //创建prod mock server\n//   createProdMockServer([...modules])\n// }\n"
  },
  {
    "path": "src/permission.ts",
    "content": "import router from '@/router'\nimport {progressClose, progressStart } from '@/hooks/use-permission'\nimport { useBasicStore } from '@/store/basic'\nimport { langTitle } from '@/hooks/use-common'\nimport settings from \"@/settings\";\n\n//路由进入前拦截\n//to:将要进入的页面 vue-router4.0 不推荐使用next()\nconst whiteList = ['/login', '/404', '/401'] // no redirect whitelist\nrouter.beforeEach(async (to) => {\n  progressStart()\n  document.title = langTitle(to.meta?.title) // i18 page title\n  const basicStore = useBasicStore()\n  //not login\n  if (!settings.isNeedLogin) {\n    basicStore.setFilterAsyncRoutes([])\n    return true\n  }\n  //1.判断token\n  if (basicStore.token) {\n    if (to.path === '/login') {\n      return '/'\n    } else {\n      basicStore.setFilterAsyncRoutes([])\n      return true\n    }\n  } else {\n    if (!whiteList.includes(to.path)) {\n      return `/login?redirect=${to.path}`\n    } else {\n      return true\n    }\n  }\n})\n//路由进入后拦截\nrouter.afterEach(() => {\n  progressClose()\n})\n"
  },
  {
    "path": "src/plugins/vite-plugin-setup-extend/index.ts",
    "content": "import { parse } from '@vue/compiler-sfc'\nimport { render } from 'ejs'\nimport type { Plugin } from 'vite'\nexport default ({ inject }): Plugin => {\n  return {\n    name: 'vite-plugin-setup-extend',\n    enforce: 'pre',\n    // configResolved(resolvedConfig) {\n    //   viteConfig = resolvedConfig\n    // },\n    async transformIndexHtml(html) {\n      const result = await render(html, { ...inject })\n      return result\n    },\n    transform(code, id) {\n      if (/\\.vue$/.test(id)) {\n        const { descriptor } = parse(code)\n        if (!descriptor?.scriptSetup?.setup) {\n          return null\n        }\n        const { lang, name } = descriptor.scriptSetup?.attrs || {}\n        const dillStr = headString(lang, name)\n        code += dillStr\n        return code\n      }\n    }\n  }\n}\n\nconst headString = (lang, name) => {\n  return `<script ${lang ? `lang=\"${lang}\"` : ''}>\nimport { defineComponent } from 'vue'\nexport default defineComponent({\n  ${name ? `name: \"${name}\",` : ''}\n})\n</script>\\n`\n}\n"
  },
  {
    "path": "src/router/index.ts",
    "content": "import { createRouter, createWebHashHistory } from 'vue-router'\nimport basicDemo from './modules/basic-demo'\nimport type { RouterTypes } from '~/basic'\nimport Layout from '@/layout/index.vue'\n\nexport const constantRoutes: RouterTypes = [\n  {\n    path: '/redirect',\n    component: Layout,\n    hidden: true,\n    children: [\n      {\n        path: '/redirect/:path(.*)',\n        component: () => import('@/views/redirect')\n      }\n    ]\n  },\n  {\n    path: '/login',\n    component: () => import('@/views/login/index.vue'),\n    hidden: true\n  },\n  {\n    path: '/404',\n    component: () => import('@/views/error-page/404.vue'),\n    hidden: true\n  },\n  {\n    path: '/401',\n    component: () => import('@/views/error-page/401.vue'),\n    hidden: true\n  },\n  {\n    path: '/',\n    component: Layout,\n    redirect: '/dashboard',\n    children: [\n      {\n        path: 'dashboard',\n        name: 'Dashboard',\n        component: () => import('@/views/dashboard/index.vue'),\n        //using el svg icon, the elSvgIcon first when at the same time using elSvgIcon and icon\n        meta: { title: 'Dashboard', icon: 'dashboard', affix: true }\n      }\n    ]\n  },\n  {\n    path: '/setting-switch',\n    component: Layout,\n    alwaysShow:true,\n    meta: { title: 'Setting Switch', elSvgIcon: 'Setting' },\n    children: [\n      {\n        path: 'index',\n        component: () => import('@/views/setting-switch/index.vue'),\n        name: 'SettingSwitch',\n        meta: { title: 'Setting Switch', elSvgIcon: 'Setting' }\n      }\n    ]\n  },\n  {\n    path: '/nested',\n    component: Layout,\n    redirect: '/nested/menu1',\n    name: 'Nested',\n    meta: {\n      title: 'Nested',\n      icon: 'nested'\n    },\n    children: [\n      {\n        path: 'menu1',\n        component: () => import('@/views/nested/menu1/index.vue'), // Parent router-view\n        name: 'Menu1',\n        meta: { title: 'Menu1' },\n        children: [\n          {\n            path: 'menu1-1',\n            component: () => import('@/views/nested/menu1/menu1-1/index.vue'),\n            name: 'Menu1-1',\n            meta: { title: 'Menu1-1' }\n          },\n          {\n            path: 'menu1-2',\n            component: () => import('@/views/nested/menu1/menu1-2/index.vue'),\n            name: 'Menu1-2',\n            meta: { title: 'Menu1-2' },\n            children: [\n              {\n                path: 'menu1-2-1',\n                component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1/index.vue'),\n                name: 'Menu1-2-1',\n                meta: { title: 'Menu1-2-1' }\n              },\n              {\n                path: 'menu1-2-2',\n                component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2/index.vue'),\n                name: 'Menu1-2-2',\n                meta: { title: 'Menu1-2-2' }\n              }\n            ]\n          },\n          {\n            path: 'menu1-3',\n            component: () => import('@/views/nested/menu1/menu1-3/index.vue'),\n            name: 'Menu1-3',\n            meta: { title: 'Menu1-3' }\n          }\n        ]\n      },\n      {\n        path: 'menu2',\n        component: () => import('@/views/nested/menu2/index.vue'),\n        name: 'Menu2',\n        meta: { title: 'menu2' }\n      }\n    ]\n  },\n  basicDemo,\n  { path: \"/:pathMatch(.*)\", redirect: \"/404\", hidden: true }\n]\n\n//角色和code数组动态路由\nexport const roleCodeRoutes: RouterTypes = [\n\n]\n/**\n * asyncRoutes\n * the routes that need to be dynamically loaded based on user roles\n */\nexport const asyncRoutes: RouterTypes = [\n  // 404 page must be placed at the end !!!\n]\n\nconst router = createRouter({\n  history: createWebHashHistory(),\n  scrollBehavior: () => ({ top: 0 }),\n  routes: constantRoutes\n})\n\nexport default router\n"
  },
  {
    "path": "src/router/modules/basic-demo.ts",
    "content": "import Layout from '@/layout/index.vue'\nconst BasicDemo = {\n  path: '/basic-demo',\n  component: Layout,\n  meta: { title: 'Basic Demo', icon: 'eye-open' },\n  alwaysShow: true,\n  children: [\n    {\n      path: 'hook',\n      component: () => import('@/views/basic-demo/hook/index.vue'),\n      name: 'Hook',\n      meta: { title: 'Hook' }\n    },\n    {\n      path: 'pinia',\n      component: () => import('@/views/basic-demo/pinia/index.vue'),\n      name: 'Pinia',\n      meta: { title: 'Pinia' }\n    },\n    {\n      path: 'mock',\n      component: () => import('@/views/basic-demo/mock/index.vue'),\n      name: 'Mock',\n      meta: { title: 'Mock' }\n    },\n    {\n      path: 'svg-icon',\n      component: () => import('@/views/basic-demo/svg-icon/index.vue'),\n      name: 'SvgIcon',\n      meta: { title: 'Svg Icon' }\n    },\n    {\n      path: 'parent-children',\n      component: () => import('@/views/basic-demo/parent-children/index.vue'),\n      name: 'Parent',\n      meta: { title: 'Parent Children' }\n    },\n    {\n      path: 'second-keep-alive',\n      component: () => import('@/views/basic-demo/keep-alive/second-keep-alive.vue'),\n      name: 'SecondKeepAlive',\n      //cachePage: cachePage when page enter, default false\n      //leaveRmCachePage: remove cachePage when page leave, default false\n      meta: { title: 'Send KeepAlive', cachePage: true, closeTabRmCache: false }\n    },\n    {\n      path: 'keep-alive-group',\n      component: () => import('@/views/basic-demo/keep-alive/index.vue'),\n      name: 'KeepAliveGroup',\n      //cachePage: cachePage when page enter, default false\n      //leaveRmCachePage: remove cachePage when page leave, default false\n      meta: { title: 'KeepAlive Group', cacheGroup: ['KeepAliveGroup', 'SecondChild', 'ThirdChild'] }\n    },\n    {\n      path: 'second-child',\n      name: 'SecondChild',\n      hidden: true,\n      component: () => import('@/views/basic-demo/keep-alive/second-child.vue'),\n      meta: { title: 'SecondChild', activeMenu: '/basic-demo/second-keep-alive' }\n    },\n    {\n      path: 'third-child',\n      name: 'ThirdChild',\n      hidden: true,\n      component: () => import('@/views/basic-demo/keep-alive/third-child.vue'),\n      meta: { title: 'ThirdChild', activeMenu: '/basic-demo/second-keep-alive' }\n    },\n    //tab-keep-alive\n    {\n      path: 'tab-keep-alive',\n      component: () => import('@/views/basic-demo/keep-alive/tab-keep-alive.vue'),\n      name: 'TabKeepAlive',\n      //closeTabRmCache: remove cachePage when tabs close, default false\n      meta: { title: 'Tab KeepAlive', cachePage: true, closeTabRmCache: true }\n    },\n    {\n      path: 'worker',\n      component: () => import('@/views/basic-demo/worker/index.vue'),\n      name: 'Worker',\n      meta: { title: 'Worker' }\n    }\n  ]\n}\n\nexport default BasicDemo\n"
  },
  {
    "path": "src/settings.ts",
    "content": "import packageJson from '../package.json'\nimport type { SettingsConfig } from '~/basic'\nexport const settings: SettingsConfig = {\n  title: packageJson.name,\n  /**\n   * @type {boolean} true | false\n   * @description Whether show the logo in sidebar\n   */\n  sidebarLogo: true,\n  /**\n   * @type {boolean} true | false\n   * @description Whether show the title in Navbar\n   */\n  showNavbarTitle: false,\n  /**\n   * @type {boolean} true | false\n   * @description Whether show the drop-down\n   */\n  ShowDropDown: true,\n  /**\n   * @type {boolean} true | false\n   * @description Whether show Hamburger\n   */\n  showHamburger: true,\n  /**\n   * @type {boolean} true | false\n   * @description Whether show the settings right-panel\n   */\n  showLeftMenu: true,\n  /**\n   * @type {boolean} true | false\n   * @description Whether show TagsView\n   */\n  showTagsView: true,\n  /**\n   * @description TagsView show number\n   */\n  tagsViewNum: 6,\n  /**\n   * @type {boolean} true | false\n   * @description Whether show the top Navbar\n   */\n  showTopNavbar: true,\n  /* page  animation related*/\n  /**\n   * @type {boolean} true | false\n   * @description Whether need animation of main area\n   */\n  mainNeedAnimation: true,\n  /**\n   * @type {boolean} true | false\n   * @description Whether need nprogress\n   */\n  isNeedNprogress: true,\n\n  /*page login or other*/\n  /**\n   * @type {boolean} true | false\n   * @description Whether need login\n   */\n  isNeedLogin: true,\n  /**\n   * @type {string} 'rbac'| 'roles' | 'code'\n   */\n  permissionMode: 'roles',\n  /**\n   * @type {boolean} true | false\n   * @description Whether  open prod mock\n   */\n  openProdMock: true,\n  /**\n   * @type {string | array} 'dev' | ['prod','test','dev'] according to the .env file props of VITE_APP_ENV\n   * @description Need show err logs component.\n   * The default is only used in the production env\n   * If you want to also use it in dev, you can pass ['dev', 'test']\n   */\n  errorLog: ['prod'],\n  /*\n   * table height(100vh-delWindowHeight)\n   * */\n  delWindowHeight: '210px',\n  /*\n   * setting dev token when  isNeedLogin is setting false\n   * */\n  tmpToken: 'tmp_token',\n\n  /*\n   * vite.config.js base config\n   * */\n  viteBasePath: './',\n\n  /*\n   * i18n setting default language\n   * en/zh\n   * */\n  defaultLanguage: 'en',\n  /*\n   *  default theme\n   * base-theme/lighting-theme/dark-theme\n   * */\n  defaultTheme: 'base-theme',\n  /*\n   * setting default defaultSize\n   * large / default /small\n   * */\n  defaultSize: 'small',\n  /*\n   * vite.config.js base config\n   * such as\n   * */\n  //平台id  2->vue3-admin-plus\n  plateFormId: 2\n}\n\nexport default settings\n"
  },
  {
    "path": "src/store/basic.ts",
    "content": "import { nextTick } from 'vue'\nimport { defineStore } from 'pinia'\nimport type { RouterTypes } from '~/basic'\nimport defaultSettings from '@/settings'\nimport router, { constantRoutes } from '@/router'\nexport const useBasicStore = defineStore('basic', {\n  state: () => {\n    return {\n      token: '',\n      getUserInfo: false,\n      userInfo: { username: '', avatar: '' }, //user info\n      //router\n      allRoutes: [] as RouterTypes,\n      buttonCodes: [],\n      filterAsyncRoutes: [],\n      roles: [] as Array<string>,\n      codes: [] as Array<number>,\n      //keep-alive\n      cachedViews: [] as Array<string>,\n      cachedViewsDeep: [] as Array<string>,\n      //other\n      sidebar: { opened: true },\n      //axios req collection\n      axiosPromiseArr: [] as Array<ObjKeys>,\n      settings: defaultSettings\n    }\n  },\n  persist: {\n    storage: localStorage,\n    paths: ['token']\n  },\n  actions: {\n    remotePromiseArrByReqUrl(reqUrl) {\n      this.$patch((state) => {\n        state.axiosPromiseArr.forEach((fItem, index) => {\n          if (fItem.url === reqUrl) {\n            state.axiosPromiseArr.splice(index, 1)\n          }\n        })\n      })\n    },\n    clearPromiseArr() {\n      this.$patch((state) => {\n        state.axiosPromiseArr=[]\n      })\n    },\n    setToken(data) {\n      this.token = data\n    },\n    setFilterAsyncRoutes(routes) {\n      this.$patch((state) => {\n        state.filterAsyncRoutes = routes\n        state.allRoutes = constantRoutes.concat(routes)\n      })\n    },\n    setUserInfo({ userInfo, roles, codes }) {\n      const { username, avatar } = userInfo\n      this.$patch((state) => {\n        state.roles = roles\n        state.codes = codes\n        state.getUserInfo = true\n        state.userInfo.username = username\n        state.userInfo.avatar = avatar\n      })\n    },\n\n    resetState() {\n      this.$patch((state) => {\n        state.token = '' //reset token\n        state.roles = []\n        state.codes = []\n        //reset router\n        state.allRoutes = []\n        state.buttonCodes = []\n        state.filterAsyncRoutes = []\n        //reset userInfo\n        state.userInfo.username = ''\n        state.userInfo.avatar = ''\n      })\n      this.getUserInfo = false\n    },\n    resetStateAndToLogin() {\n      this.resetState()\n      nextTick(() => {\n        router.push({ path: '/login' })\n      })\n    },\n    setSidebarOpen(data) {\n      this.$patch((state) => {\n        state.sidebar.opened = data\n      })\n    },\n    setToggleSideBar() {\n      this.$patch((state) => {\n        state.sidebar.opened = !state.sidebar.opened\n      })\n    },\n\n    /*keepAlive缓存*/\n    addCachedView(view) {\n      this.$patch((state) => {\n        if (state.cachedViews.includes(view)) return\n        state.cachedViews.push(view)\n      })\n    },\n\n    delCachedView(view) {\n      this.$patch((state) => {\n        const index = state.cachedViews.indexOf(view)\n        index > -1 && state.cachedViews.splice(index, 1)\n      })\n    },\n    /*third  keepAlive*/\n    addCachedViewDeep(view) {\n      this.$patch((state) => {\n        if (state.cachedViewsDeep.includes(view)) return\n        state.cachedViewsDeep.push(view)\n      })\n    },\n    delCacheViewDeep(view) {\n      this.$patch((state) => {\n        const index = state.cachedViewsDeep.indexOf(view)\n        index > -1 && state.cachedViewsDeep.splice(index, 1)\n      })\n    }\n  }\n})\n"
  },
  {
    "path": "src/store/config.ts",
    "content": "import { defineStore } from 'pinia'\nimport { langTitle } from '@/hooks/use-common'\nimport settings from '@/settings'\nimport { toggleHtmlClass } from '@/theme/utils'\nimport { i18n } from '@/lang'\nexport const useConfigStore = defineStore('config', {\n  state: () => {\n    return {\n      language: settings.defaultLanguage,\n      theme: settings.defaultTheme,\n      size: settings.defaultSize\n    }\n  },\n  persist: {\n    storage: localStorage,\n    paths: ['language', 'theme', 'size']\n  },\n  actions: {\n    setTheme(data: string) {\n      this.theme = data\n      toggleHtmlClass(data)\n    },\n    setSize(data: string) {\n      this.size = data\n    },\n    setLanguage(lang: string, title) {\n      const { locale }: any = i18n.global\n      this.language = lang\n      locale.value = lang\n      document.title = langTitle(title) // i18 page title\n    }\n  }\n})\n"
  },
  {
    "path": "src/store/tags-view.ts",
    "content": "import { defineStore } from 'pinia'\nimport setting from '@/settings'\nexport const useTagsViewStore = defineStore('tagsView', {\n  state: () => {\n    return {\n      visitedViews: [] //tag标签数组\n    }\n  },\n  actions: {\n    addVisitedView(view) {\n      this.$patch((state: any) => {\n        //判断添加的标签存在直接返回\n        if (state.visitedViews.some((v) => v.path === view.path)) return\n        //添加的数量如果大于 setting.tagsViewNum,则替换最后一个元素，否则在visitedViews数组后插入一个元素\n        if (state.visitedViews.length >= setting.tagsViewNum) {\n          state.visitedViews.pop()\n          state.visitedViews.push(\n            Object.assign({}, view, {\n              title: view.meta.title || 'no-name'\n            })\n          )\n        } else {\n          state.visitedViews.push(\n            Object.assign({}, view, {\n              title: view.meta.title || 'no-name'\n            })\n          )\n        }\n      })\n    },\n    delVisitedView(view) {\n      return new Promise((resolve) => {\n        this.$patch((state: any) => {\n          //匹配view.path元素将其删除\n          for (const [i, v] of state.visitedViews.entries()) {\n            if (v.path === view.path) {\n              state.visitedViews.splice(i, 1)\n              break\n            }\n          }\n          resolve([...state.visitedViews])\n        })\n      })\n    },\n    delOthersVisitedViews(view) {\n      return new Promise((resolve) => {\n        this.$patch((state) => {\n          state.visitedViews = state.visitedViews.filter((v: ObjKeys) => {\n            return v.meta.affix || v.path === view.path\n          })\n          resolve([...state.visitedViews])\n        })\n      })\n    },\n    delAllVisitedViews() {\n      return new Promise((resolve) => {\n        this.$patch((state) => {\n          // keep affix tags\n          state.visitedViews = state.visitedViews.filter((tag: ObjKeys) => tag.meta?.affix)\n          resolve([...state.visitedViews])\n        })\n      })\n    }\n  }\n})\n"
  },
  {
    "path": "src/styles/index.scss",
    "content": "//scss 语法糖包含常用的布局方式 flex column\n@import './scss-suger.scss';\n//重置 element-plus 样式\n@import 'reset-elemenet-plus.scss';\n//动画文件\n@import './transition.scss';\n@import './project-style.scss';\n\n//reset style\nbody {\n  height: 100%;\n  margin: 0;\n  padding: 0;\n  font-size: 14px;\n}\n* {\n  box-sizing: border-box;\n}\n*::before,\n*::after {\n  box-sizing: border-box;\n}\na:focus,\na:active {\n  outline: none;\n}\na,\na:focus,\na:hover {\n  cursor: pointer;\n  color: inherit;\n  text-decoration: none;\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n  line-height: 1;\n  font-weight: 400;\n  margin: 0;\n  padding: 0;\n}\nspan,\noutput {\n  display: inline-block;\n  line-height: 1;\n}\n\n//scroll\n@mixin main-show-wh() {\n  /* css 声明 */\n  height: calc(90vh - #{var(--nav-bar-height)} - #{var(--tag-view-height)} - #{calc(var(--app-main-padding) * 2)});\n  width: 100%;\n}\n.scroll-y {\n  @include main-show-wh();\n  overflow-y: auto;\n}\n.scroll-x {\n  @include main-show-wh();\n  overflow-x: auto;\n}\n.scroll-xy {\n  @include main-show-wh();\n  overflow: auto;\n}\n\n\n\n\n\n\n"
  },
  {
    "path": "src/styles/init-loading.css",
    "content": "/*开屏loading样式设置*/\n.loader-wrapper{\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n  height: 80vh;\n}\n\n.loading-gif{\n\n}\n\n.load_title{\n  margin-top: 30px;\n  font-size: 16px;\n}\n"
  },
  {
    "path": "src/styles/project-style.scss",
    "content": ".project-page-style {\n  background: #fff;\n  padding: 20px;\n  padding-top: 0;\n}\n\n.query-page-style {\n  background: #fff;\n  padding: 20px;\n}\n\n//汽包\n.triangle {\n  position: relative;\n  left: 150px;\n  width: 0;\n  height: 0;\n  border: 6px solid transparent;\n  border-bottom-color: #fafafa;\n}\n\n//table relative\n.table-operation-btn {\n  span {\n    cursor: pointer;\n    color: var(--el-color-primary);\n    display: inline-block;\n    padding: 0 6px;\n  }\n}\n//新增底部 btn\n.footer-btn {\n  position: fixed;\n  width: calc(100% - var(--side-bar-width));\n  text-align: center;\n  border-top: 1px solid var(--lineB3);\n  background: #ffffff;\n  padding: 12px 0;\n  margin-left: 0;\n  bottom: 0;\n  z-index: 11;\n  left: var(--side-bar-width) px;\n}\n"
  },
  {
    "path": "src/styles/reset-elemenet-plus.scss",
    "content": "//leave the padding of  el-scroll sidebar\n#Sidebar{\n  .el-scrollbar__view {\n    padding-bottom: 80px;\n  }\n  .el-scrollbar{\n    --el-menu-base-level-padding:15px;\n  }\n\n}\n\n\n\n.el-dialog__body{\n  padding-top:0!important;\n}\n\n\n//.el-loading-spinner .circular {\n//  display: none !important;\n//}\n//.el-loading-spinner {\n//  background: url('../assets/gif/loading.gif') no-repeat;\n//  background-size: 300px 300px;\n//  width: 300px!important;\n//  height: 300px!important;\n//  position: fixed;\n//  top: 50%;\n//  left: 50%;\n//  transform: translate(-50%, -50%);\n//  z-index: 10;\n//}\n\n\n/* loading loading遮罩层\n------------------------------- */\n.el-loading-mask {\n  // position: relative  !important;\n  .el-loading-spinner {\n    position: fixed  !important;\n    background: #ffffff !important;\n    width: 200px !important;\n    height: 120px !important;\n    border-radius: 8px !important;\n    left: 50% !important;\n    transform: translate(-50%, -50%) !important;\n    padding-top: 20px !important;\n    box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);\n    i {\n      font-size: 20px;\n    }\n    .el-loading-text {\n      margin: 12px 0 0 0 !important;\n      //color: set-color(brand) !important;\n    }\n  }\n}\n"
  },
  {
    "path": "src/styles/scss-suger.scss",
    "content": "/*脱落文档流定位*/\n.center-50 {\n  //居中定位\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%);\n  z-index: 10;\n}\n.center-top60 {\n  position: absolute;\n  top: 60%;\n  left: 50%;\n  transform: translate(-50%, -60%);\n  z-index: 10;\n}\n.center-top70 {\n  position: absolute;\n  top: 70%;\n  left: 50%;\n  transform: translate(-50%, -70%);\n  z-index: 10;\n}\n.center-top80 {\n  position: absolute;\n  top: 80%;\n  left: 50%;\n  transform: translate(-50%, -80%);\n  z-index: 10;\n}\n.center-top90 {\n  position: absolute;\n  top: 80%;\n  left: 50%;\n  transform: translate(-50%, -90%);\n  z-index: 10;\n}\n/*fixed*/\n.fixed-center-50 {\n  //居中定位\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%);\n  z-index: 10;\n}\n.fixed-center-top60 {\n  position: fixed;\n  top: 60%;\n  left: 50%;\n  transform: translate(-50%, -60%);\n  z-index: 10;\n}\n.fixed-center-top70 {\n  position: fixed;\n  top: 70%;\n  left: 50%;\n  transform: translate(-50%, -70%);\n  z-index: 10;\n}\n.fixed-center-top80 {\n  position: fixed;\n  top: 80%;\n  left: 50%;\n  transform: translate(-50%, -80%);\n  z-index: 10;\n}\n.fixed-center-top90 {\n  position: fixed;\n  top: 90%;\n  left: 50%;\n  transform: translate(-50%, -90%);\n  z-index: 10;\n}\n.fixed-center-top95 {\n  position: fixed;\n  top: 95%;\n  left: 50%;\n  transform: translate(-50%, -95%);\n  z-index: 10;\n}\n\n/*\nflex布局 第一个字母为主轴\n*/\n//start\n.rowSS {\n  display: flex;\n  flex-direction: row;\n  justify-content: flex-start;\n  align-items: flex-start;\n}\n.rowSC {\n  display: flex;\n  flex-direction: row;\n  justify-content: flex-start;\n  align-items: center;\n}\n.rowSE {\n  display: flex;\n  flex-direction: row;\n  justify-content: flex-start;\n  align-items: flex-end;\n}\n//space-between\n.rowBS {\n  display: flex;\n  flex-direction: row;\n  justify-content: space-between;\n  align-items: flex-start;\n}\n.rowBC {\n  display: flex;\n  flex-direction: row;\n  justify-content: space-between;\n  align-items: center;\n}\n.rowBE {\n  display: flex;\n  flex-direction: row;\n  justify-content: space-between;\n  align-items: flex-end;\n}\n//space-around\n.rowAS {\n  display: flex;\n  flex-direction: row;\n  justify-content: space-around;\n  align-items: flex-start;\n}\n.rowAC {\n  display: flex;\n  flex-direction: row;\n  justify-content: space-around;\n  align-items: center;\n}\n.rowAE {\n  display: flex;\n  flex-direction: row;\n  justify-content: space-around;\n  align-items: flex-end;\n}\n//center\n.rowCS {\n  display: flex;\n  flex-direction: row;\n  justify-content: center;\n  align-items: flex-start;\n}\n.rowCC {\n  display: flex;\n  flex-direction: row;\n  justify-content: center;\n  align-items: center;\n}\n\n.rowCE {\n  display: flex;\n  flex-direction: row;\n  justify-content: center;\n  align-items: flex-end;\n}\n\n/*col*/\n//start\n.columnSS {\n  display: flex;\n  flex-direction: column;\n  justify-content: flex-start;\n  align-items: flex-start;\n}\n.columnSC {\n  display: flex;\n  flex-direction: column;\n  justify-content: flex-start;\n  align-items: center;\n}\n.columnSE {\n  display: flex;\n  flex-direction: column;\n  justify-content: flex-start;\n  align-items: flex-end;\n}\n//space-between\n.columnBS {\n  display: flex;\n  flex-direction: column;\n  justify-content: space-between;\n  align-items: flex-start;\n}\n.columnBC {\n  display: flex;\n  flex-direction: column;\n  justify-content: space-between;\n  align-items: center;\n}\n.columnBE {\n  display: flex;\n  flex-direction: column;\n  justify-content: space-between;\n  align-items: flex-end;\n}\n//space-around\n.columnAS {\n  display: flex;\n  flex-direction: column;\n  justify-content: space-around;\n  align-items: flex-start;\n}\n.columnAC {\n  display: flex;\n  flex-direction: column;\n  justify-content: space-around;\n  align-items: center;\n}\n.columnAE {\n  display: flex;\n  flex-direction: column;\n  justify-content: space-around;\n  align-items: flex-end;\n}\n//center\n.columnCS {\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: flex-start;\n}\n.columnCC {\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n}\n.columnCE {\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: flex-end;\n}\n\n//*图标\n.star-icon {\n  color: #f56c6c;\n  font-size: 14px;\n  margin-right: 4px;\n}\n\n.fix-btn-to-bottom {\n  position: fixed;\n  bottom: 0;\n  left: 50%;\n  transform: translate(-50%, 0);\n  z-index: 10;\n  height: 60px;\n  background: #fff;\n  width: 100vw;\n}\n\n//table操作栏\n.table-operation-btn {\n  span {\n    //点击样式\n    cursor: pointer;\n    color: #477ef5;\n  }\n}\n\n//table操作栏\n.btn-click-style {\n  //点击样式\n  cursor: pointer;\n  color: #477ef5;\n}\n"
  },
  {
    "path": "src/styles/transition.scss",
    "content": "// vue global transition css define\n/* sidebar-logo-fade */\n.sidebar-logo-fade-enter-active {\n  transition: opacity var(--logo-switch-duration);\n}\n.sidebar-logo-fade-enter-from,\n.sidebar-logo-fade-leave-to {\n  opacity: 0;\n}\n\n/* fade-transform AppMain*/\n.fade-transform-leave-active,\n.fade-transform-enter-active {\n  transition: all var(--page-transform-duration);\n}\n\n.fade-transform-enter-from {\n  opacity: 0;\n  transform: translateX(-10px);\n}\n\n.fade-transform-leave-to {\n  opacity: 0;\n  transform: translateX(10px);\n}\n.fade-transform-active {\n  position: absolute;\n}\n\n/* breadcrumb transition */\n.breadcrumb-enter-active,\n.breadcrumb-leave-active {\n  transition: all var(--breadcrumb-change-duration);\n}\n\n.breadcrumb-enter-from,\n.breadcrumb-leave-active {\n  opacity: 0;\n  transform: translateX(10px);\n}\n\n.breadcrumb-leave-active {\n  position: absolute;\n}\n"
  },
  {
    "path": "src/theme/base/custom/ct-css-vars.scss",
    "content": "html.base-theme {\n  /*element-plus section */\n  --el-menu-active-color: #409eff;\n  --el-menu-text-color: #bfcbd9;\n  --el-menu-hover-text-color: var(--el-color-primary);\n  --el-menu-bg-color: #304156;\n  --el-menu-hover-bg-color: #263445;\n  --el-menu-item-height: 56px;\n  --el-menu-border-color: none;\n  /*layout section*/\n  //layout\n  --layout-border-left-color: #ddd;\n  //Breadcrumb\n  --breadcrumb-no-redirect: #97a8be;\n  //Hamburger\n  --hamburger-color: #2b2f3a;\n  --hamburger-width: 20px;\n  --hamburger-height: 20px;\n  //Sidebar\n  --sidebar-el-icon-size: 20px;\n  --sidebar-logo-background: #2b2f3a;\n  --sidebar-logo-color: #ff9901;\n  --sidebar-logo-width: 32px;\n  --sidebar-logo-height: 32px;\n  --sidebar-logo-title-color: #fff;\n  --side-bar-width: 210px;\n  --side-bar-border-right-color: #eee;\n  //TagsView\n  --tags-view-background: #fff;\n  --tags-view-border-bottom: #eee;\n  --tags-view-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);\n  --tags-view-item-background: #fff;\n  --tags-view-item-border-color: #d8dce5;\n  --tags-view-item-color: #495060;\n  --tag-view-height: 32px;\n  --tags-view-item-active-background: #42b983;\n  --tags-view-item-active-color: #fff;\n  --tags-view-item-active-border-color: #42b983;\n  --tags-view-contextmenu-background: #fff;\n  --tags-view-contextmenu-color: #333;\n  --tags-view-contextmenu-box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);\n  --tags-view-contextmenu-hover-background: #eee;\n  //close-icon\n  --tags-view-close-icon-hover-background: #b4bccc;\n  --tags-view-close-icon-hover-color: #fff;\n  //AppMain.vue\n  --app-main-padding: 20px;\n  --app-main-background: #fff;\n  //Navbar.vue\n  --nav-bar-height: 50px;\n  --nav-bar-background: #fff;\n  --nav-bar-box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);\n  --nav-bar-right-menu-background: #fff;\n\n  //transition 动画\n  //侧边栏切换动画时长\n  --sideBar-switch-duration: 0.2s;\n  //logo切换动画时长\n  --logo-switch-duration: 1s;\n  //页面动画时长\n  --page-transform-duration: 0.2s;\n  //面包屑导航动画时长\n  --breadcrumb-change-duration: 0.2s;\n\n  //进度条颜色\n  --pregress-bar-color: transparent;\n}\n"
  },
  {
    "path": "src/theme/base/element-plus/button.scss",
    "content": "html.base-theme {\n  .at-button-low {\n    --el-button-text-color: #262626;\n    --el-button-bg-color: #ffffff;\n    --el-button-border-color: #d9d9d9;\n    --el-button-outline-color: #d9d9d9;\n\n    --el-button-hover-text-color: #c72210;\n    --el-button-hover-link-text-color: #c72210;\n    --el-button-hover-bg-color: #ffece6;\n    --el-button-hover-border-color: transparent;\n\n    --el-button-active-color: #a8150a;\n    --el-button-active-bg-color: #a8150a;\n    --el-button-active-border-color: transparent;\n\n    --el-button-disabled-text-color: #a6a6a6;\n    --el-button-disabled-bg-color: #ffece6;\n    --el-button-disabled-border-color: #c72210;\n    //loading\n    --el-button-loading-text-color: #c72210;\n    --el-button-loading-bg-color: #ffece6;\n    --el-button-loading-border-color: #c72210;\n  }\n\n  .at-button-middle {\n    --el-button-text-color: #c72210;\n    --el-button-bg-color: #ffece6;\n    --el-button-border-color: #c72210;\n    --el-button-outline-color: #c72210;\n\n    --el-button-hover-text-color: #ffffff;\n    --el-button-hover-link-text-color: #ffffff;\n    --el-button-hover-bg-color: #c72210;\n    --el-button-hover-border-color: #c72210;\n\n    --el-button-active-color: #ffffff;\n    --el-button-active-bg-color: #a8150a;\n    --el-button-active-border-color: #a8150a;\n\n    --el-button-disabled-text-color: #a6a6a6;\n    --el-button-disabled-bg-color: #ffffff;\n    --el-button-disabled-border-color: #d9d9d9;\n\n    //loading\n    --el-button-loading-text-color: #c72210;\n    --el-button-loading-bg-color: #ffece6;\n    --el-button-loading-border-color: #c72210;\n  }\n\n  .at-button-height {\n    --el-button-text-color: #ffffff;\n    --el-button-bg-color: #c72210;\n    --el-button-border-color: transparent;\n    --el-button-outline-color: transparent;\n\n    --el-button-hover-text-color: #ffffff;\n    --el-button-hover-link-text-color: #ffffff;\n    --el-button-hover-bg-color: #dd715b;\n    --el-button-hover-border-color: #c72210;\n\n    --el-button-active-color: #ffffff;\n    --el-button-active-bg-color: #a8150a;\n    --el-button-active-border-color: transparent;\n\n    --el-button-disabled-text-color: #a6a6a6;\n    --el-button-disabled-bg-color: #f5f5f5;\n    --el-button-disabled-border-color: transparent;\n\n    //loading\n    --el-button-loading-text-color: #ffffff;\n    --el-button-loading-bg-color: #c72210;\n    --el-button-loading-border-color: transparent;\n  }\n\n  .at-button-text {\n    --el-button-text-color: #477ef5;\n    --el-fill-color-light: transparent;\n    --el-fill-color: transparent;\n\n    --el-button-hover-text-color: #86b2f9;\n\n    --el-button-active-color: #2c59cb;\n\n    --el-button-disabled-text-color: #a6a6a6;\n\n    //loading\n    --el-button-loading-text-color: #477ef5;\n  }\n\n  .el-button {\n    //default\n    --el-button-size: 36px;\n    height: var(--el-button-size);\n    padding: 8px 30px;\n    font-size: 14px;\n    //loading\n    .is-loading {\n      color: var(--el-button-loading-text-color);\n      background-color: var(--el-button-loading-bg-color);\n      border-color: var(--el-button-loading-border-color);\n    }\n  }\n\n  .el-button--small {\n    --el-button-size: 27px;\n    height: var(--el-button-size);\n    padding: 5px 24px;\n    font-size: 12px;\n  }\n\n  .el-button--large {\n    --el-button-size: 40px;\n    height: var(--el-button-size);\n    padding: 10px 30px;\n    font-size: 14px;\n  }\n\n  .el-button + .el-button {\n    margin-left: 12px;\n  }\n}\n"
  },
  {
    "path": "src/theme/base/element-plus/checkbox.scss",
    "content": "html.china-red {\n  .el-checkbox {\n    --el-checkbox-font-size: 14px;\n    --el-checkbox-font-weight: var(--el-font-weight-primary);\n    --el-checkbox-text-color: #262626;\n    --el-checkbox-input-height: 14px;\n    --el-checkbox-input-width: 14px;\n    --el-checkbox-border-radius: var(--el-border-radius-small);\n    --el-checkbox-bg-color: var(--el-fill-color-blank);\n    --el-checkbox-input-border: var(--el-border);\n\n    //disabled\n    --el-checkbox-disabled-border-color: var(--el-border-color);\n    --el-checkbox-disabled-input-fill: var(--el-fill-color-light);\n    --el-checkbox-disabled-icon-color: var(--el-text-color-placeholder);\n    --el-checkbox-disabled-checked-input-fill: var(--el-border-color-extra-light);\n    --el-checkbox-disabled-checked-input-border-color: var(--el-border-color);\n    --el-checkbox-disabled-checked-icon-color: var(--el-text-color-placeholder);\n\n    //check\n    --el-checkbox-checked-text-color: #262626;\n    --el-checkbox-checked-input-border-color: transparent;\n    --el-checkbox-checked-bg-color: #c72210;\n    --el-checkbox-checked-icon-color: #ffffff;\n    --el-checkbox-input-border-color-hover: #c72210;\n  }\n}\n"
  },
  {
    "path": "src/theme/base/element-plus/css-vars.scss",
    "content": "@use 'sass:map';\n\n@use './var' as *;\n@use '../../mixins/var'  as *;\n@use '../../mixins/mixins'  as *;\n\nhtml.china-red {\n  color-scheme: china-red;\n  @each $type in (primary, success, warning, danger, error, info) {\n    @include set-css-color-rgb($colors, $type);\n  }\n\n  @each $type in (primary, success, warning, danger, error, info) {\n    @include set-css-color-type($colors, $type);\n  }\n  //--el-color-primary: #c72210;\n}\n"
  },
  {
    "path": "src/theme/base/element-plus/form.scss",
    "content": "html.china-red {\n  //date\n  .el-date-range-picker {\n    --el-datepicker-text-color: var(--el-text-color-regular);\n    --el-datepicker-off-text-color: var(--el-text-color-placeholder);\n    --el-datepicker-header-text-color: var(--el-text-color-regular);\n    --el-datepicker-icon-color: var(--el-text-color-primary);\n    --el-datepicker-border-color: var(--el-disabled-border-color);\n    --el-datepicker-inner-border-color: var(--el-border-color-light);\n    --el-datepicker-inrange-bg-color: #ffece6;\n    --el-datepicker-inrange-hover-bg-color: var(--el-border-color-extra-light);\n    --el-datepicker-active-color: var(--el-color-primary);\n    --el-datepicker-hover-text-color: var(--el-color-primary);\n  }\n\n  .el-select-dropdown__item.hover,\n  .el-select-dropdown__item:hover {\n    background-color: #ffece6;\n  }\n}\n"
  },
  {
    "path": "src/theme/base/element-plus/pagination.scss",
    "content": "html.china-red {\n  .el-pagination {\n    --el-text-color-regular: #8c8c8c;\n    --el-pagination-font-size: 14px;\n    --el-pagination-bg-color: var(--el-fill-color-blank);\n    --el-pagination-text-color: var(--el-text-color-primary);\n    --el-pagination-border-radius: 3px;\n    --el-pagination-button-color: var(--el-text-color-primary);\n    --el-pagination-button-width: 32px;\n    --el-pagination-button-height: 32px;\n    --el-pagination-button-disabled-color: var(--el-text-color-placeholder);\n    --el-pagination-button-disabled-bg-color: var(--el-fill-color-blank);\n    --el-pagination-button-bg-color: var(--el-fill-color);\n    --el-pagination-hover-color: var(--el-color-primary);\n    --el-pagination-height-extra-small: 24px;\n    --el-pagination-line-height-extra-small: var(--el-pagination-height-extra-small);\n    white-space: nowrap;\n    padding: 2px 5px;\n    color: var(--el-pagination-text-color);\n    font-weight: 400;\n    display: flex;\n    align-items: center;\n  }\n\n  .el-pagination__total {\n    margin-right: 16px;\n    font-weight: 400;\n    color: var(--el-text-color-regular);\n  }\n}\n"
  },
  {
    "path": "src/theme/base/element-plus/redio.scss",
    "content": "html.china-red {\n  .el-radio {\n    --el-radio-font-size: var(--el-font-size-base);\n    --el-radio-text-color: #262626;\n    --el-radio-font-weight: var(--el-font-weight-primary);\n    --el-radio-input-height: 14px;\n    --el-radio-input-width: 14px;\n    --el-radio-input-border-radius: var(--el-border-radius-circle);\n    --el-radio-input-bg-color: var(--el-fill-color-blank);\n    --el-radio-input-border: var(--el-border);\n    --el-radio-input-border-color: transparent;\n    //--el-radio-input-border-color-hover: transparent;\n  }\n\n  .el-radio__input.is-checked + .el-radio__label {\n    color: #262626;\n  }\n}\n"
  },
  {
    "path": "src/theme/base/element-plus/table.scss",
    "content": "html.china-red {\n  .el-table {\n    --el-table-border-color: #f0f0f0;\n    --el-table-border: 1px solid #f0f0f0;\n    --el-table-text-color: var(--el-text-color-regular);\n    --el-table-header-text-color: var(--el-text-color-secondary);\n    --el-table-row-hover-bg-color: #ffece6;\n    --el-table-current-row-bg-color: var(--el-color-primary-light-9);\n    --el-table-header-bg-color: #fafafa;\n    --el-table-fixed-box-shadow: var(--el-box-shadow-light);\n    --el-table-bg-color: var(--el-fill-color-blank);\n    --el-table-tr-bg-color: var(--el-fill-color-blank);\n    --el-table-expanded-cell-bg-color: var(--el-fill-color-blank);\n    --el-table-fixed-left-column: inset 10px 0 10px -10px rgba(0, 0, 0, 0.15);\n    --el-table-fixed-right-column: inset -10px 0 10px -10px rgba(0, 0, 0, 0.15);\n  }\n}\n"
  },
  {
    "path": "src/theme/base/element-plus/var.scss",
    "content": "/* Element Chalk Variables */\n@use 'sass:math';\n@use 'sass:map';\n@use '../../mixins/function.scss' as *;\n\n// types\n$types: primary, success, warning, danger, error, info;\n\n// change color\n$colors: () !default;\n$colors: map.deep-merge(\n  (\n    'white': #ffffff,\n    'black': #000000,\n    'primary': (\n      'base': #c72210//#409eff\n    ),\n    'success': (\n      'base': #45b207\n    ),\n    'warning': (\n      'base': #ec8828\n    ),\n    'danger': (\n      'base': #f56c6c\n    ),\n    'error': (\n      'base': #d24934\n    ),\n    'info': (\n      'base': #909399\n    )\n  ),\n  $colors\n);\n\n$color-white: map.get($colors, 'white') !default;\n$color-black: map.get($colors, 'black') !default;\n$color-primary: map.get($colors, 'primary', 'base') !default;\n$color-success: map.get($colors, 'success', 'base') !default;\n$color-warning: map.get($colors, 'warning', 'base') !default;\n$color-danger: map.get($colors, 'danger', 'base') !default;\n$color-error: map.get($colors, 'error', 'base') !default;\n$color-info: map.get($colors, 'info', 'base') !default;\n\n//$colors添加 --el-color-primary-light-7\n@mixin set-color-mix-level($type, $number, $mode: 'light', $mix-color: $color-white) {\n  $colors: map.deep-merge(\n    (\n      $type: (\n        '#{$mode}-#{$number}': mix($mix-color, map.get($colors, $type, 'base'), math.percentage(math.div($number, 10)))\n      )\n    ),\n    $colors\n  ) !global;\n}\n\n// $colors.primary.light-i\n@each $type in $types {\n  @for $i from 1 through 9 {\n    @include set-color-mix-level($type, $i, 'light', $color-white);\n  }\n}\n"
  },
  {
    "path": "src/theme/base/index.scss",
    "content": "/*china-red*/\n//element-plus\n@use \"./element-plus/css-vars\";\n@use \"./element-plus/var\";\n@use \"./element-plus/button\";\n@use \"./element-plus/checkbox\";\n@use \"./element-plus/redio\";\n@use \"./element-plus/pagination\";\n@use \"./element-plus/form\";\n@use \"./element-plus/table\";\n\n//custom\n@use \"./custom/ct-css-vars\";\n"
  },
  {
    "path": "src/theme/china-red/custom/ct-css-vars.scss",
    "content": "html.china-red {\n  --el-menu-active-color: var(--el-color-primary);\n  --el-menu-text-color: var(--el-text-color-primary);\n  --el-menu-hover-text-color: var(--el-menu-active-color);\n  --el-menu-bg-color: var(--el-fill-color-blank);\n  --el-menu-hover-bg-color: var(--el-color-primary-light-9);\n  --el-menu-item-height: 56px;\n  --el-menu-sub-item-height: calc(var(--el-menu-item-height) - 6px);\n  --el-menu-horizontal-sub-item-height: 36px;\n  --el-menu-item-font-size: var(--el-font-size-base);\n  --el-menu-item-hover-fill: var(--el-color-primary-light-9);\n  --el-menu-border-color: none;\n  --el-menu-base-level-padding: 20px;\n  --el-menu-level-padding: 20px;\n  --el-menu-icon-width: 24px;\n\n  .el-menu-item.is-active {\n    color: var(--el-menu-active-color);\n    background-color: #ffece6;\n  }\n\n  .el-menu-item:hover {\n    background-color: var(--el-menu-hover-bg-color);\n    color: var(--el-menu-active-color);\n  }\n  /*element-plus section */\n  //--el-menu-active-color: #409eff;\n  //--el-menu-text-color: #bfcbd9;\n  //--el-menu-hover-text-color: var(--el-color-primary);\n  //--el-menu-bg-color: #304156;\n  //--el-menu-hover-bg-color: #263445;\n  //--el-menu-item-height: 56px;\n\n  /*layout section*/\n  //layout\n  --layout-border-left-color: #ddd;\n  //Breadcrumb\n  --breadcrumb-no-redirect: #97a8be;\n  //Hamburger\n  --hamburger-width: 20px;\n  --hamburger-height: 20px;\n  //Sidebar\n  --sidebar-el-icon-size: 20px;\n  --sidebar-logo-background: #fff;\n  --sidebar-logo-color: #ff9901;\n  --sidebar-logo-width: 32px;\n  --sidebar-logo-height: 32px;\n  --sidebar-logo-title-color: #2b2f3a;\n  --side-bar-width: 210px;\n  --side-bar-border-right-color: #eee;\n  //TagsView\n  --tags-view-background: #fff;\n  --tags-view-border-bottom: #d8dce5;\n  --tags-view-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);\n  --tags-view-item-background: #fff;\n  --tags-view-item-border-color: #d8dce5;\n  --tags-view-item-color: #495060;\n  --tag-view-height: 32px;\n  --tags-view-item-active-background: #42b983;\n  --tags-view-item-active-color: #fff;\n  --tags-view-item-active-border-color: #42b983;\n  --tags-view-contextmenu-background: #fff;\n  --tags-view-contextmenu-color: #333;\n  --tags-view-contextmenu-box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);\n  --tags-view-contextmenu-hover-background: #eee;\n  //close-icon\n  --tags-view-close-icon-hover-background: #b4bccc;\n  --tags-view-close-icon-hover-color: #fff;\n  //AppMain.vue\n  --app-main-padding: 20px;\n  --app-main-background: #fff;\n  //Navbar.vue\n  --nav-bar-height: 50px;\n  --nav-bar-background: #fff;\n  --nav-bar-box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);\n  --nav-bar-right-menu-background: #fff;\n\n  //transition 动画\n  //侧边栏切换动画时长\n  --sideBar-switch-duration: 0.2s;\n  //logo切换动画时长\n  --logo-switch-duration: 1.5s;\n  //页面动画时长\n  --page-transform-duration: 0.2s;\n  //面包屑导航动画时长\n  --breadcrumb-change-duration: 0.2s;\n\n  //进度条颜色\n  --pregress-bar-color: transparent;\n}\n"
  },
  {
    "path": "src/theme/china-red/element-plus/button.scss",
    "content": "html.china-red {\n  color-scheme: china-red;\n  .at-button-low {\n    --el-button-text-color: #262626;\n    --el-button-bg-color: #ffffff;\n    --el-button-border-color: #d9d9d9;\n    --el-button-outline-color: #d9d9d9;\n\n    --el-button-hover-text-color: #c72210;\n    --el-button-hover-link-text-color: #c72210;\n    --el-button-hover-bg-color: #ffece6;\n    --el-button-hover-border-color: transparent;\n\n    --el-button-active-color: #a8150a;\n    --el-button-active-bg-color: #a8150a;\n    --el-button-active-border-color: transparent;\n\n    --el-button-disabled-text-color: #a6a6a6;\n    --el-button-disabled-bg-color: #ffece6;\n    --el-button-disabled-border-color: #c72210;\n    //loading\n    --el-button-loading-text-color: #c72210;\n    --el-button-loading-bg-color: #ffece6;\n    --el-button-loading-border-color: #c72210;\n  }\n\n  .at-button-middle {\n    --el-button-text-color: #c72210;\n    --el-button-bg-color: #ffece6;\n    --el-button-border-color: #c72210;\n    --el-button-outline-color: #c72210;\n\n    --el-button-hover-text-color: #ffffff;\n    --el-button-hover-link-text-color: #ffffff;\n    --el-button-hover-bg-color: #c72210;\n    --el-button-hover-border-color: #c72210;\n\n    --el-button-active-color: #ffffff;\n    --el-button-active-bg-color: #a8150a;\n    --el-button-active-border-color: #a8150a;\n\n    --el-button-disabled-text-color: #a6a6a6;\n    --el-button-disabled-bg-color: #ffffff;\n    --el-button-disabled-border-color: #d9d9d9;\n\n    //loading\n    --el-button-loading-text-color: #c72210;\n    --el-button-loading-bg-color: #ffece6;\n    --el-button-loading-border-color: #c72210;\n  }\n\n  .at-button-height {\n    --el-button-text-color: #ffffff;\n    --el-button-bg-color: #c72210;\n    --el-button-border-color: transparent;\n    --el-button-outline-color: transparent;\n\n    --el-button-hover-text-color: #ffffff;\n    --el-button-hover-link-text-color: #ffffff;\n    --el-button-hover-bg-color: #dd715b;\n    --el-button-hover-border-color: #c72210;\n\n    --el-button-active-color: #ffffff;\n    --el-button-active-bg-color: #a8150a;\n    --el-button-active-border-color: transparent;\n\n    --el-button-disabled-text-color: #a6a6a6;\n    --el-button-disabled-bg-color: #f5f5f5;\n    --el-button-disabled-border-color: transparent;\n\n    //loading\n    --el-button-loading-text-color: #ffffff;\n    --el-button-loading-bg-color: #c72210;\n    --el-button-loading-border-color: transparent;\n  }\n\n  .at-button-text {\n    --el-button-text-color: #477ef5;\n    --el-fill-color-light: transparent;\n    --el-fill-color: transparent;\n\n    --el-button-hover-text-color: #86b2f9;\n\n    --el-button-active-color: #2c59cb;\n\n    --el-button-disabled-text-color: #a6a6a6;\n\n    //loading\n    --el-button-loading-text-color: #477ef5;\n  }\n\n  .el-button {\n    //default\n    --el-button-size: 36px;\n    height: var(--el-button-size);\n    padding: 8px 30px;\n    font-size: 14px;\n    //loading\n    .is-loading {\n      color: var(--el-button-loading-text-color);\n      background-color: var(--el-button-loading-bg-color);\n      border-color: var(--el-button-loading-border-color);\n    }\n  }\n\n  .el-button--small {\n    --el-button-size: 27px;\n    height: var(--el-button-size);\n    padding: 5px 24px;\n    font-size: 12px;\n  }\n\n  .el-button--large {\n    --el-button-size: 40px;\n    height: var(--el-button-size);\n    padding: 10px 30px;\n    font-size: 14px;\n  }\n\n  .el-button + .el-button {\n    margin-left: 12px;\n  }\n}\n"
  },
  {
    "path": "src/theme/china-red/element-plus/checkbox.scss",
    "content": "html.china-red {\n  .el-checkbox {\n    --el-checkbox-font-size: 14px;\n    --el-checkbox-font-weight: var(--el-font-weight-primary);\n    --el-checkbox-text-color: #262626;\n    --el-checkbox-input-height: 14px;\n    --el-checkbox-input-width: 14px;\n    --el-checkbox-border-radius: var(--el-border-radius-small);\n    --el-checkbox-bg-color: var(--el-fill-color-blank);\n    --el-checkbox-input-border: var(--el-border);\n\n    //disabled\n    --el-checkbox-disabled-border-color: var(--el-border-color);\n    --el-checkbox-disabled-input-fill: var(--el-fill-color-light);\n    --el-checkbox-disabled-icon-color: var(--el-text-color-placeholder);\n    --el-checkbox-disabled-checked-input-fill: var(--el-border-color-extra-light);\n    --el-checkbox-disabled-checked-input-border-color: var(--el-border-color);\n    --el-checkbox-disabled-checked-icon-color: var(--el-text-color-placeholder);\n\n    //check\n    --el-checkbox-checked-text-color: #262626;\n    --el-checkbox-checked-input-border-color: transparent;\n    --el-checkbox-checked-bg-color: #c72210;\n    --el-checkbox-checked-icon-color: #ffffff;\n    --el-checkbox-input-border-color-hover: #c72210;\n  }\n}\n"
  },
  {
    "path": "src/theme/china-red/element-plus/css-vars.scss",
    "content": "@use 'sass:map';\n\n@use './var' as *;\n@use '../../mixins/var'  as *;\n@use '../../mixins/mixins'  as *;\n\nhtml.china-red {\n  color-scheme: china-red;\n  @each $type in (primary, success, warning, danger, error, info) {\n    @include set-css-color-rgb($colors, $type);\n  }\n\n  @each $type in (primary, success, warning, danger, error, info) {\n    @include set-css-color-type($colors, $type);\n  }\n  //--el-color-primary: #c72210;\n}\n"
  },
  {
    "path": "src/theme/china-red/element-plus/form.scss",
    "content": "html.china-red {\n  //date\n  .el-date-range-picker {\n    --el-datepicker-text-color: var(--el-text-color-regular);\n    --el-datepicker-off-text-color: var(--el-text-color-placeholder);\n    --el-datepicker-header-text-color: var(--el-text-color-regular);\n    --el-datepicker-icon-color: var(--el-text-color-primary);\n    --el-datepicker-border-color: var(--el-disabled-border-color);\n    --el-datepicker-inner-border-color: var(--el-border-color-light);\n    --el-datepicker-inrange-bg-color: #ffece6;\n    --el-datepicker-inrange-hover-bg-color: var(--el-border-color-extra-light);\n    --el-datepicker-active-color: var(--el-color-primary);\n    --el-datepicker-hover-text-color: var(--el-color-primary);\n  }\n\n  .el-select-dropdown__item.hover,\n  .el-select-dropdown__item:hover {\n    background-color: #ffece6;\n  }\n}\n"
  },
  {
    "path": "src/theme/china-red/element-plus/pagination.scss",
    "content": "html.china-red {\n  .el-pagination {\n    --el-text-color-regular: #8c8c8c;\n    --el-pagination-font-size: 14px;\n    --el-pagination-bg-color: var(--el-fill-color-blank);\n    --el-pagination-text-color: var(--el-text-color-primary);\n    --el-pagination-border-radius: 3px;\n    --el-pagination-button-color: var(--el-text-color-primary);\n    --el-pagination-button-width: 32px;\n    --el-pagination-button-height: 32px;\n    --el-pagination-button-disabled-color: var(--el-text-color-placeholder);\n    --el-pagination-button-disabled-bg-color: var(--el-fill-color-blank);\n    --el-pagination-button-bg-color: var(--el-fill-color);\n    --el-pagination-hover-color: var(--el-color-primary);\n    --el-pagination-height-extra-small: 24px;\n    --el-pagination-line-height-extra-small: var(--el-pagination-height-extra-small);\n    white-space: nowrap;\n    padding: 2px 5px;\n    color: var(--el-pagination-text-color);\n    font-weight: 400;\n    display: flex;\n    align-items: center;\n  }\n\n  .el-pagination__total {\n    margin-right: 16px;\n    font-weight: 400;\n    color: var(--el-text-color-regular);\n  }\n}\n"
  },
  {
    "path": "src/theme/china-red/element-plus/redio.scss",
    "content": "html.china-red {\n  .el-radio {\n    --el-radio-font-size: var(--el-font-size-base);\n    --el-radio-text-color: #262626;\n    --el-radio-font-weight: var(--el-font-weight-primary);\n    --el-radio-input-height: 14px;\n    --el-radio-input-width: 14px;\n    --el-radio-input-border-radius: var(--el-border-radius-circle);\n    --el-radio-input-bg-color: var(--el-fill-color-blank);\n    --el-radio-input-border: var(--el-border);\n    --el-radio-input-border-color: transparent;\n    //--el-radio-input-border-color-hover: transparent;\n  }\n\n  .el-radio__input.is-checked + .el-radio__label {\n    color: #262626;\n  }\n}\n"
  },
  {
    "path": "src/theme/china-red/element-plus/table.scss",
    "content": "html.china-red {\n  .el-table {\n    --el-table-border-color: #f0f0f0;\n    --el-table-border: 1px solid #f0f0f0;\n    --el-table-text-color: var(--el-text-color-regular);\n    --el-table-header-text-color: var(--el-text-color-secondary);\n    --el-table-row-hover-bg-color: #ffece6;\n    --el-table-current-row-bg-color: var(--el-color-primary-light-9);\n    --el-table-header-bg-color: #fafafa;\n    --el-table-fixed-box-shadow: var(--el-box-shadow-light);\n    --el-table-bg-color: var(--el-fill-color-blank);\n    --el-table-tr-bg-color: var(--el-fill-color-blank);\n    --el-table-expanded-cell-bg-color: var(--el-fill-color-blank);\n    --el-table-fixed-left-column: inset 10px 0 10px -10px rgba(0, 0, 0, 0.15);\n    --el-table-fixed-right-column: inset -10px 0 10px -10px rgba(0, 0, 0, 0.15);\n  }\n}\n"
  },
  {
    "path": "src/theme/china-red/element-plus/var.scss",
    "content": "/* Element Chalk Variables */\n@use 'sass:math';\n@use 'sass:map';\n@use '../../mixins/function.scss' as *;\n\n// types\n$types: primary, success, warning, danger, error, info;\n\n// change color\n$colors: () !default;\n$colors: map.deep-merge(\n  (\n    'white': #ffffff,\n    'black': #000000,\n    'primary': (\n      'base': #c72210//#409eff\n    ),\n    'success': (\n      'base': #45b207\n    ),\n    'warning': (\n      'base': #ec8828\n    ),\n    'danger': (\n      'base': #f56c6c\n    ),\n    'error': (\n      'base': #d24934\n    ),\n    'info': (\n      'base': #909399\n    )\n  ),\n  $colors\n);\n\n$color-white: map.get($colors, 'white') !default;\n$color-black: map.get($colors, 'black') !default;\n$color-primary: map.get($colors, 'primary', 'base') !default;\n$color-success: map.get($colors, 'success', 'base') !default;\n$color-warning: map.get($colors, 'warning', 'base') !default;\n$color-danger: map.get($colors, 'danger', 'base') !default;\n$color-error: map.get($colors, 'error', 'base') !default;\n$color-info: map.get($colors, 'info', 'base') !default;\n\n//$colors添加 --el-color-primary-light-7\n@mixin set-color-mix-level($type, $number, $mode: 'light', $mix-color: $color-white) {\n  $colors: map.deep-merge(\n    (\n      $type: (\n        '#{$mode}-#{$number}': mix($mix-color, map.get($colors, $type, 'base'), math.percentage(math.div($number, 10)))\n      )\n    ),\n    $colors\n  ) !global;\n}\n\n// $colors.primary.light-i\n@each $type in $types {\n  @for $i from 1 through 9 {\n    @include set-color-mix-level($type, $i, 'light', $color-white);\n  }\n}\n"
  },
  {
    "path": "src/theme/china-red/index.scss",
    "content": "/*china-red*/\n//element-plus\n@use \"./element-plus/css-vars\";\n@use \"./element-plus/var\";\n@use \"./element-plus/button\";\n@use \"./element-plus/checkbox\";\n@use \"./element-plus/redio\";\n@use \"./element-plus/pagination\";\n@use \"./element-plus/form\";\n@use \"./element-plus/table\";\n\n//custom\n@use \"./custom/ct-css-vars\";\n"
  },
  {
    "path": "src/theme/dark/custom/ct-css-vars.scss",
    "content": "html.dark {\n  /*element-plus section */\n  --el-menu-active-color: #409eff;\n  --el-menu-text-color: #bfcbd9;\n  --el-menu-hover-text-color: var(--el-color-primary);\n  --el-menu-bg-color: #304156;\n  --el-menu-hover-bg-color: #263445;\n  --el-menu-item-height: 56px;\n  --el-menu-border-color: none;\n  /*layout section*/\n  //layout\n  --layout-border-left-color: #ddd;\n  //Breadcrumb\n  --breadcrumb-no-redirect: #97a8be;\n  //Hamburger\n  --hamburger-color: #fff;\n  --hamburger-width: 20px;\n  --hamburger-height: 20px;\n  --el-text-color-primary: #fff;\n  //Sidebar\n  --sidebar-el-icon-size: 20px;\n  --sidebar-logo-background: #2b2f3a;\n  --sidebar-logo-color: #ff9901;\n  --sidebar-logo-width: 32px;\n  --sidebar-logo-height: 32px;\n  --sidebar-logo-title-color: #fff;\n  --side-bar-width: 210px;\n  --side-bar-border-right-color: #2b2f3a;\n  //TagsView\n  --tags-view-background: #304156;\n  --tags-view-border-bottom: #2b2f3a;\n  --tags-view-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);\n  --tags-view-item-background: #fff;\n  --tags-view-item-border-color: #d8dce5;\n  --tags-view-item-color: #495060;\n  --tag-view-height: 32px;\n  --tags-view-item-active-background: #42b983;\n  --tags-view-item-active-color: #fff;\n  --tags-view-item-active-border-color: #42b983;\n  --tags-view-contextmenu-background: #fff;\n  --tags-view-contextmenu-color: #333;\n  --tags-view-contextmenu-box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);\n  --tags-view-contextmenu-hover-background: #eee;\n  //close-icon\n  --tags-view-close-icon-hover-background: #b4bccc;\n  --tags-view-close-icon-hover-color: #fff;\n  //AppMain.vue\n  --app-main-padding: 0px;\n  --app-main-background: #304156;\n  //Navbar.vue\n  --nav-bar-height: 50px;\n  --nav-bar-background: #2b2f3a;\n  --nav-bar-box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);\n  --nav-bar-right-menu-background: #2b2f3a;\n\n  //transition 动画\n  //侧边栏切换动画时长\n  --sideBar-switch-duration: 0.2s;\n  //logo切换动画时长\n  --logo-switch-duration: 1s;\n  //页面动画时长\n  --page-transform-duration: 0.2s;\n  //面包屑导航动画时长\n  --breadcrumb-change-duration: 0.2s;\n\n  //进度条颜色\n  --pregress-bar-color: transparent;\n}\n"
  },
  {
    "path": "src/theme/dark/element-plus/button.scss",
    "content": "html.china-red {\n  color-scheme: china-red;\n  .at-button-low {\n    --el-button-text-color: #262626;\n    --el-button-bg-color: #ffffff;\n    --el-button-border-color: #d9d9d9;\n    --el-button-outline-color: #d9d9d9;\n\n    --el-button-hover-text-color: #c72210;\n    --el-button-hover-link-text-color: #c72210;\n    --el-button-hover-bg-color: #ffece6;\n    --el-button-hover-border-color: transparent;\n\n    --el-button-active-color: #a8150a;\n    --el-button-active-bg-color: #a8150a;\n    --el-button-active-border-color: transparent;\n\n    --el-button-disabled-text-color: #a6a6a6;\n    --el-button-disabled-bg-color: #ffece6;\n    --el-button-disabled-border-color: #c72210;\n    //loading\n    --el-button-loading-text-color: #c72210;\n    --el-button-loading-bg-color: #ffece6;\n    --el-button-loading-border-color: #c72210;\n  }\n\n  .at-button-middle {\n    --el-button-text-color: #c72210;\n    --el-button-bg-color: #ffece6;\n    --el-button-border-color: #c72210;\n    --el-button-outline-color: #c72210;\n\n    --el-button-hover-text-color: #ffffff;\n    --el-button-hover-link-text-color: #ffffff;\n    --el-button-hover-bg-color: #c72210;\n    --el-button-hover-border-color: #c72210;\n\n    --el-button-active-color: #ffffff;\n    --el-button-active-bg-color: #a8150a;\n    --el-button-active-border-color: #a8150a;\n\n    --el-button-disabled-text-color: #a6a6a6;\n    --el-button-disabled-bg-color: #ffffff;\n    --el-button-disabled-border-color: #d9d9d9;\n\n    //loading\n    --el-button-loading-text-color: #c72210;\n    --el-button-loading-bg-color: #ffece6;\n    --el-button-loading-border-color: #c72210;\n  }\n\n  .at-button-height {\n    --el-button-text-color: #ffffff;\n    --el-button-bg-color: #c72210;\n    --el-button-border-color: transparent;\n    --el-button-outline-color: transparent;\n\n    --el-button-hover-text-color: #ffffff;\n    --el-button-hover-link-text-color: #ffffff;\n    --el-button-hover-bg-color: #dd715b;\n    --el-button-hover-border-color: #c72210;\n\n    --el-button-active-color: #ffffff;\n    --el-button-active-bg-color: #a8150a;\n    --el-button-active-border-color: transparent;\n\n    --el-button-disabled-text-color: #a6a6a6;\n    --el-button-disabled-bg-color: #f5f5f5;\n    --el-button-disabled-border-color: transparent;\n\n    //loading\n    --el-button-loading-text-color: #ffffff;\n    --el-button-loading-bg-color: #c72210;\n    --el-button-loading-border-color: transparent;\n  }\n\n  .at-button-text {\n    --el-button-text-color: #477ef5;\n    --el-fill-color-light: transparent;\n    --el-fill-color: transparent;\n\n    --el-button-hover-text-color: #86b2f9;\n\n    --el-button-active-color: #2c59cb;\n\n    --el-button-disabled-text-color: #a6a6a6;\n\n    //loading\n    --el-button-loading-text-color: #477ef5;\n  }\n\n  .el-button {\n    //default\n    --el-button-size: 36px;\n    height: var(--el-button-size);\n    padding: 8px 30px;\n    font-size: 14px;\n    //loading\n    .is-loading {\n      color: var(--el-button-loading-text-color);\n      background-color: var(--el-button-loading-bg-color);\n      border-color: var(--el-button-loading-border-color);\n    }\n  }\n\n  .el-button--small {\n    --el-button-size: 27px;\n    height: var(--el-button-size);\n    padding: 5px 24px;\n    font-size: 12px;\n  }\n\n  .el-button--large {\n    --el-button-size: 40px;\n    height: var(--el-button-size);\n    padding: 10px 30px;\n    font-size: 14px;\n  }\n\n  .el-button + .el-button {\n    margin-left: 12px;\n  }\n}\n"
  },
  {
    "path": "src/theme/dark/element-plus/checkbox.scss",
    "content": "html.china-red {\n  .el-checkbox {\n    --el-checkbox-font-size: 14px;\n    --el-checkbox-font-weight: var(--el-font-weight-primary);\n    --el-checkbox-text-color: #262626;\n    --el-checkbox-input-height: 14px;\n    --el-checkbox-input-width: 14px;\n    --el-checkbox-border-radius: var(--el-border-radius-small);\n    --el-checkbox-bg-color: var(--el-fill-color-blank);\n    --el-checkbox-input-border: var(--el-border);\n\n    //disabled\n    --el-checkbox-disabled-border-color: var(--el-border-color);\n    --el-checkbox-disabled-input-fill: var(--el-fill-color-light);\n    --el-checkbox-disabled-icon-color: var(--el-text-color-placeholder);\n    --el-checkbox-disabled-checked-input-fill: var(--el-border-color-extra-light);\n    --el-checkbox-disabled-checked-input-border-color: var(--el-border-color);\n    --el-checkbox-disabled-checked-icon-color: var(--el-text-color-placeholder);\n\n    //check\n    --el-checkbox-checked-text-color: #262626;\n    --el-checkbox-checked-input-border-color: transparent;\n    --el-checkbox-checked-bg-color: #c72210;\n    --el-checkbox-checked-icon-color: #ffffff;\n    --el-checkbox-input-border-color-hover: #c72210;\n  }\n}\n"
  },
  {
    "path": "src/theme/dark/element-plus/css-vars.css",
    "content": ""
  },
  {
    "path": "src/theme/dark/element-plus/css-vars.scss",
    "content": "@use 'sass:map';\n\n@use './var' as *;\n@use '../../mixins/var'  as *;\n@use '../../mixins/mixins'  as *;\n\nhtml.china-red {\n  color-scheme: china-red;\n  @each $type in (primary, success, warning, danger, error, info) {\n    @include set-css-color-rgb($colors, $type);\n  }\n\n  @each $type in (primary, success, warning, danger, error, info) {\n    @include set-css-color-type($colors, $type);\n  }\n  //--el-color-primary: #c72210;\n}\n"
  },
  {
    "path": "src/theme/dark/element-plus/form.scss",
    "content": "html.china-red {\n  //date\n  .el-date-range-picker {\n    --el-datepicker-text-color: var(--el-text-color-regular);\n    --el-datepicker-off-text-color: var(--el-text-color-placeholder);\n    --el-datepicker-header-text-color: var(--el-text-color-regular);\n    --el-datepicker-icon-color: var(--el-text-color-primary);\n    --el-datepicker-border-color: var(--el-disabled-border-color);\n    --el-datepicker-inner-border-color: var(--el-border-color-light);\n    --el-datepicker-inrange-bg-color: #ffece6;\n    --el-datepicker-inrange-hover-bg-color: var(--el-border-color-extra-light);\n    --el-datepicker-active-color: var(--el-color-primary);\n    --el-datepicker-hover-text-color: var(--el-color-primary);\n  }\n\n  .el-select-dropdown__item.hover,\n  .el-select-dropdown__item:hover {\n    background-color: #ffece6;\n  }\n}\n"
  },
  {
    "path": "src/theme/dark/element-plus/pagination.scss",
    "content": "html.china-red {\n  .el-pagination {\n    --el-text-color-regular: #8c8c8c;\n    --el-pagination-font-size: 14px;\n    --el-pagination-bg-color: var(--el-fill-color-blank);\n    --el-pagination-text-color: var(--el-text-color-primary);\n    --el-pagination-border-radius: 3px;\n    --el-pagination-button-color: var(--el-text-color-primary);\n    --el-pagination-button-width: 32px;\n    --el-pagination-button-height: 32px;\n    --el-pagination-button-disabled-color: var(--el-text-color-placeholder);\n    --el-pagination-button-disabled-bg-color: var(--el-fill-color-blank);\n    --el-pagination-button-bg-color: var(--el-fill-color);\n    --el-pagination-hover-color: var(--el-color-primary);\n    --el-pagination-height-extra-small: 24px;\n    --el-pagination-line-height-extra-small: var(--el-pagination-height-extra-small);\n    white-space: nowrap;\n    padding: 2px 5px;\n    color: var(--el-pagination-text-color);\n    font-weight: 400;\n    display: flex;\n    align-items: center;\n  }\n\n  .el-pagination__total {\n    margin-right: 16px;\n    font-weight: 400;\n    color: var(--el-text-color-regular);\n  }\n}\n"
  },
  {
    "path": "src/theme/dark/element-plus/redio.scss",
    "content": "html.china-red {\n  .el-radio {\n    --el-radio-font-size: var(--el-font-size-base);\n    --el-radio-text-color: #262626;\n    --el-radio-font-weight: var(--el-font-weight-primary);\n    --el-radio-input-height: 14px;\n    --el-radio-input-width: 14px;\n    --el-radio-input-border-radius: var(--el-border-radius-circle);\n    --el-radio-input-bg-color: var(--el-fill-color-blank);\n    --el-radio-input-border: var(--el-border);\n    --el-radio-input-border-color: transparent;\n    //--el-radio-input-border-color-hover: transparent;\n  }\n\n  .el-radio__input.is-checked + .el-radio__label {\n    color: #262626;\n  }\n}\n"
  },
  {
    "path": "src/theme/dark/element-plus/table.scss",
    "content": "html.china-red {\n  .el-table {\n    --el-table-border-color: #f0f0f0;\n    --el-table-border: 1px solid #f0f0f0;\n    --el-table-text-color: var(--el-text-color-regular);\n    --el-table-header-text-color: var(--el-text-color-secondary);\n    --el-table-row-hover-bg-color: #ffece6;\n    --el-table-current-row-bg-color: var(--el-color-primary-light-9);\n    --el-table-header-bg-color: #fafafa;\n    --el-table-fixed-box-shadow: var(--el-box-shadow-light);\n    --el-table-bg-color: var(--el-fill-color-blank);\n    --el-table-tr-bg-color: var(--el-fill-color-blank);\n    --el-table-expanded-cell-bg-color: var(--el-fill-color-blank);\n    --el-table-fixed-left-column: inset 10px 0 10px -10px rgba(0, 0, 0, 0.15);\n    --el-table-fixed-right-column: inset -10px 0 10px -10px rgba(0, 0, 0, 0.15);\n  }\n}\n"
  },
  {
    "path": "src/theme/dark/element-plus/var.scss",
    "content": "/* Element Chalk Variables */\n@use 'sass:math';\n@use 'sass:map';\n@use '../../mixins/function.scss' as *;\n\n// types\n$types: primary, success, warning, danger, error, info;\n\n// change color\n$colors: () !default;\n$colors: map.deep-merge(\n  (\n    'white': #ffffff,\n    'black': #000000,\n    'primary': (\n      'base': #c72210//#409eff\n    ),\n    'success': (\n      'base': #45b207\n    ),\n    'warning': (\n      'base': #ec8828\n    ),\n    'danger': (\n      'base': #f56c6c\n    ),\n    'error': (\n      'base': #d24934\n    ),\n    'info': (\n      'base': #909399\n    )\n  ),\n  $colors\n);\n\n$color-white: map.get($colors, 'white') !default;\n$color-black: map.get($colors, 'black') !default;\n$color-primary: map.get($colors, 'primary', 'base') !default;\n$color-success: map.get($colors, 'success', 'base') !default;\n$color-warning: map.get($colors, 'warning', 'base') !default;\n$color-danger: map.get($colors, 'danger', 'base') !default;\n$color-error: map.get($colors, 'error', 'base') !default;\n$color-info: map.get($colors, 'info', 'base') !default;\n\n//$colors添加 --el-color-primary-light-7\n@mixin set-color-mix-level($type, $number, $mode: 'light', $mix-color: $color-white) {\n  $colors: map.deep-merge(\n    (\n      $type: (\n        '#{$mode}-#{$number}': mix($mix-color, map.get($colors, $type, 'base'), math.percentage(math.div($number, 10)))\n      )\n    ),\n    $colors\n  ) !global;\n}\n\n// $colors.primary.light-i\n@each $type in $types {\n  @for $i from 1 through 9 {\n    @include set-color-mix-level($type, $i, 'light', $color-white);\n  }\n}\n"
  },
  {
    "path": "src/theme/dark/index.scss",
    "content": "/*china-red*/\n//element-plus\n//@use \"./element-plus/css-vars\";\n//@use \"./element-plus/var\";\n//@use \"./element-plus/button\";\n//@use \"./element-plus/checkbox\";\n//@use \"./element-plus/redio\";\n//@use \"./element-plus/pagination\";\n//@use \"./element-plus/form\";\n//@use \"./element-plus/table\";\n\n//custom\n@use \"./custom/ct-css-vars\";\n"
  },
  {
    "path": "src/theme/index.css",
    "content": ""
  },
  {
    "path": "src/theme/index.scss",
    "content": "// we can add this to custom namespace, default is 'el'\n//@forward \"element-plus/theme-chalk/src/mixins/config.scss\" with (\n//  $namespace: \"el\"\n//);\n\n//base-theme\n@use \"./base\";\n//theme style such as dark-theme lighting\n@use \"./dark\";\n@use \"./lighting\";\n@use \"./china-red\";\n"
  },
  {
    "path": "src/theme/lighting/custom/ct-css-vars.scss",
    "content": "html.lighting-theme {\n  /*element-plus section */\n  //--el-menu-active-color: #409eff;\n  //--el-menu-text-color: #bfcbd9;\n  //--el-menu-hover-text-color: var(--el-color-primary);\n  //--el-menu-bg-color: #304156;\n  //--el-menu-hover-bg-color: #263445;\n  //--el-menu-item-height: 56px;\n  --el-menu-border-color: none;\n  /*layout section*/\n  //layout\n  --layout-border-left-color: #ddd;\n  //Breadcrumb\n  --breadcrumb-no-redirect: #97a8be;\n  //Hamburger\n  --hamburger-color: #2b2f3a;\n  --hamburger-width: 20px;\n  --hamburger-height: 20px;\n  //Sidebar\n  --sidebar-el-icon-size: 20px;\n  --sidebar-logo-background: #fff;\n  --sidebar-logo-color: #ff9901;\n  --sidebar-logo-width: 32px;\n  --sidebar-logo-height: 32px;\n  --sidebar-logo-title-color: #2b2f3a;\n  --side-bar-width: 210px;\n  --side-bar-border-right-color: #eee;\n  //TagsView\n  --tags-view-background: #fff;\n  --tags-view-border-bottom: #d8dce5;\n  --tags-view-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);\n  --tags-view-item-background: #fff;\n  --tags-view-item-border-color: #d8dce5;\n  --tags-view-item-color: #495060;\n  --tag-view-height: 32px;\n  --tags-view-item-active-background: #42b983;\n  --tags-view-item-active-color: #fff;\n  --tags-view-item-active-border-color: #42b983;\n  --tags-view-contextmenu-background: #fff;\n  --tags-view-contextmenu-color: #333;\n  --tags-view-contextmenu-box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);\n  --tags-view-contextmenu-hover-background: #eee;\n  //close-icon\n  --tags-view-close-icon-hover-background: #b4bccc;\n  --tags-view-close-icon-hover-color: #fff;\n  //AppMain.vue\n  --app-main-padding: 20px;\n  --app-main-background: #fff;\n  //Navbar.vue\n  --nav-bar-height: 50px;\n  --nav-bar-background: #fff;\n  --nav-bar-box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);\n  --nav-bar-right-menu-background: #fff;\n\n  //transition 动画\n  //侧边栏切换动画时长\n  --sideBar-switch-duration: 0.2s;\n  //logo切换动画时长\n  --logo-switch-duration: 0.5s;\n  //页面动画时长\n  --page-transform-duration: 0.2s;\n  //面包屑导航动画时长\n  --breadcrumb-change-duration: 0.2s;\n\n  //进度条颜色\n  --pregress-bar-color: transparent;\n}\n"
  },
  {
    "path": "src/theme/lighting/element-plus/button.scss",
    "content": "html.china-red {\n  color-scheme: china-red;\n  .at-button-low {\n    --el-button-text-color: #262626;\n    --el-button-bg-color: #ffffff;\n    --el-button-border-color: #d9d9d9;\n    --el-button-outline-color: #d9d9d9;\n\n    --el-button-hover-text-color: #c72210;\n    --el-button-hover-link-text-color: #c72210;\n    --el-button-hover-bg-color: #ffece6;\n    --el-button-hover-border-color: transparent;\n\n    --el-button-active-color: #a8150a;\n    --el-button-active-bg-color: #a8150a;\n    --el-button-active-border-color: transparent;\n\n    --el-button-disabled-text-color: #a6a6a6;\n    --el-button-disabled-bg-color: #ffece6;\n    --el-button-disabled-border-color: #c72210;\n    //loading\n    --el-button-loading-text-color: #c72210;\n    --el-button-loading-bg-color: #ffece6;\n    --el-button-loading-border-color: #c72210;\n  }\n\n  .at-button-middle {\n    --el-button-text-color: #c72210;\n    --el-button-bg-color: #ffece6;\n    --el-button-border-color: #c72210;\n    --el-button-outline-color: #c72210;\n\n    --el-button-hover-text-color: #ffffff;\n    --el-button-hover-link-text-color: #ffffff;\n    --el-button-hover-bg-color: #c72210;\n    --el-button-hover-border-color: #c72210;\n\n    --el-button-active-color: #ffffff;\n    --el-button-active-bg-color: #a8150a;\n    --el-button-active-border-color: #a8150a;\n\n    --el-button-disabled-text-color: #a6a6a6;\n    --el-button-disabled-bg-color: #ffffff;\n    --el-button-disabled-border-color: #d9d9d9;\n\n    //loading\n    --el-button-loading-text-color: #c72210;\n    --el-button-loading-bg-color: #ffece6;\n    --el-button-loading-border-color: #c72210;\n  }\n\n  .at-button-height {\n    --el-button-text-color: #ffffff;\n    --el-button-bg-color: #c72210;\n    --el-button-border-color: transparent;\n    --el-button-outline-color: transparent;\n\n    --el-button-hover-text-color: #ffffff;\n    --el-button-hover-link-text-color: #ffffff;\n    --el-button-hover-bg-color: #dd715b;\n    --el-button-hover-border-color: #c72210;\n\n    --el-button-active-color: #ffffff;\n    --el-button-active-bg-color: #a8150a;\n    --el-button-active-border-color: transparent;\n\n    --el-button-disabled-text-color: #a6a6a6;\n    --el-button-disabled-bg-color: #f5f5f5;\n    --el-button-disabled-border-color: transparent;\n\n    //loading\n    --el-button-loading-text-color: #ffffff;\n    --el-button-loading-bg-color: #c72210;\n    --el-button-loading-border-color: transparent;\n  }\n\n  .at-button-text {\n    --el-button-text-color: #477ef5;\n    --el-fill-color-light: transparent;\n    --el-fill-color: transparent;\n\n    --el-button-hover-text-color: #86b2f9;\n\n    --el-button-active-color: #2c59cb;\n\n    --el-button-disabled-text-color: #a6a6a6;\n\n    //loading\n    --el-button-loading-text-color: #477ef5;\n  }\n\n  .el-button {\n    //default\n    --el-button-size: 36px;\n    height: var(--el-button-size);\n    padding: 8px 30px;\n    font-size: 14px;\n    //loading\n    .is-loading {\n      color: var(--el-button-loading-text-color);\n      background-color: var(--el-button-loading-bg-color);\n      border-color: var(--el-button-loading-border-color);\n    }\n  }\n\n  .el-button--small {\n    --el-button-size: 27px;\n    height: var(--el-button-size);\n    padding: 5px 24px;\n    font-size: 12px;\n  }\n\n  .el-button--large {\n    --el-button-size: 40px;\n    height: var(--el-button-size);\n    padding: 10px 30px;\n    font-size: 14px;\n  }\n\n  .el-button + .el-button {\n    margin-left: 12px;\n  }\n}\n"
  },
  {
    "path": "src/theme/lighting/element-plus/checkbox.scss",
    "content": "html.china-red {\n  .el-checkbox {\n    --el-checkbox-font-size: 14px;\n    --el-checkbox-font-weight: var(--el-font-weight-primary);\n    --el-checkbox-text-color: #262626;\n    --el-checkbox-input-height: 14px;\n    --el-checkbox-input-width: 14px;\n    --el-checkbox-border-radius: var(--el-border-radius-small);\n    --el-checkbox-bg-color: var(--el-fill-color-blank);\n    --el-checkbox-input-border: var(--el-border);\n\n    //disabled\n    --el-checkbox-disabled-border-color: var(--el-border-color);\n    --el-checkbox-disabled-input-fill: var(--el-fill-color-light);\n    --el-checkbox-disabled-icon-color: var(--el-text-color-placeholder);\n    --el-checkbox-disabled-checked-input-fill: var(--el-border-color-extra-light);\n    --el-checkbox-disabled-checked-input-border-color: var(--el-border-color);\n    --el-checkbox-disabled-checked-icon-color: var(--el-text-color-placeholder);\n\n    //check\n    --el-checkbox-checked-text-color: #262626;\n    --el-checkbox-checked-input-border-color: transparent;\n    --el-checkbox-checked-bg-color: #c72210;\n    --el-checkbox-checked-icon-color: #ffffff;\n    --el-checkbox-input-border-color-hover: #c72210;\n  }\n}\n"
  },
  {
    "path": "src/theme/lighting/element-plus/css-vars.css",
    "content": ""
  },
  {
    "path": "src/theme/lighting/element-plus/css-vars.scss",
    "content": "@use 'sass:map';\n\n@use './var' as *;\n@use '../../mixins/var'  as *;\n@use '../../mixins/mixins'  as *;\n\nhtml.china-red {\n  color-scheme: china-red;\n  @each $type in (primary, success, warning, danger, error, info) {\n    @include set-css-color-rgb($colors,$type);\n  }\n\n  @each $type in (primary, success, warning, danger, error, info) {\n    @include set-css-color-type($colors, $type);\n  }\n  //--el-color-primary: #c72210;\n}\n"
  },
  {
    "path": "src/theme/lighting/element-plus/form.scss",
    "content": "html.china-red {\n  //date\n  .el-date-range-picker {\n    --el-datepicker-text-color: var(--el-text-color-regular);\n    --el-datepicker-off-text-color: var(--el-text-color-placeholder);\n    --el-datepicker-header-text-color: var(--el-text-color-regular);\n    --el-datepicker-icon-color: var(--el-text-color-primary);\n    --el-datepicker-border-color: var(--el-disabled-border-color);\n    --el-datepicker-inner-border-color: var(--el-border-color-light);\n    --el-datepicker-inrange-bg-color: #ffece6;\n    --el-datepicker-inrange-hover-bg-color: var(--el-border-color-extra-light);\n    --el-datepicker-active-color: var(--el-color-primary);\n    --el-datepicker-hover-text-color: var(--el-color-primary);\n  }\n\n  .el-select-dropdown__item.hover,\n  .el-select-dropdown__item:hover {\n    background-color: #ffece6;\n  }\n}\n"
  },
  {
    "path": "src/theme/lighting/element-plus/pagination.scss",
    "content": "html.china-red {\n  .el-pagination {\n    --el-text-color-regular: #8c8c8c;\n    --el-pagination-font-size: 14px;\n    --el-pagination-bg-color: var(--el-fill-color-blank);\n    --el-pagination-text-color: var(--el-text-color-primary);\n    --el-pagination-border-radius: 3px;\n    --el-pagination-button-color: var(--el-text-color-primary);\n    --el-pagination-button-width: 32px;\n    --el-pagination-button-height: 32px;\n    --el-pagination-button-disabled-color: var(--el-text-color-placeholder);\n    --el-pagination-button-disabled-bg-color: var(--el-fill-color-blank);\n    --el-pagination-button-bg-color: var(--el-fill-color);\n    --el-pagination-hover-color: var(--el-color-primary);\n    --el-pagination-height-extra-small: 24px;\n    --el-pagination-line-height-extra-small: var(--el-pagination-height-extra-small);\n    white-space: nowrap;\n    padding: 2px 5px;\n    color: var(--el-pagination-text-color);\n    font-weight: 400;\n    display: flex;\n    align-items: center;\n  }\n\n  .el-pagination__total {\n    margin-right: 16px;\n    font-weight: 400;\n    color: var(--el-text-color-regular);\n  }\n}\n"
  },
  {
    "path": "src/theme/lighting/element-plus/redio.scss",
    "content": "html.china-red {\n  .el-radio {\n    --el-radio-font-size: var(--el-font-size-base);\n    --el-radio-text-color: #262626;\n    --el-radio-font-weight: var(--el-font-weight-primary);\n    --el-radio-input-height: 14px;\n    --el-radio-input-width: 14px;\n    --el-radio-input-border-radius: var(--el-border-radius-circle);\n    --el-radio-input-bg-color: var(--el-fill-color-blank);\n    --el-radio-input-border: var(--el-border);\n    --el-radio-input-border-color: transparent;\n    //--el-radio-input-border-color-hover: transparent;\n  }\n\n  .el-radio__input.is-checked + .el-radio__label {\n    color: #262626;\n  }\n}\n"
  },
  {
    "path": "src/theme/lighting/element-plus/table.scss",
    "content": "html.china-red {\n  .el-table {\n    --el-table-border-color: #f0f0f0;\n    --el-table-border: 1px solid #f0f0f0;\n    --el-table-text-color: var(--el-text-color-regular);\n    --el-table-header-text-color: var(--el-text-color-secondary);\n    --el-table-row-hover-bg-color: #ffece6;\n    --el-table-current-row-bg-color: var(--el-color-primary-light-9);\n    --el-table-header-bg-color: #fafafa;\n    --el-table-fixed-box-shadow: var(--el-box-shadow-light);\n    --el-table-bg-color: var(--el-fill-color-blank);\n    --el-table-tr-bg-color: var(--el-fill-color-blank);\n    --el-table-expanded-cell-bg-color: var(--el-fill-color-blank);\n    --el-table-fixed-left-column: inset 10px 0 10px -10px rgba(0, 0, 0, 0.15);\n    --el-table-fixed-right-column: inset -10px 0 10px -10px rgba(0, 0, 0, 0.15);\n  }\n}\n"
  },
  {
    "path": "src/theme/lighting/element-plus/var.scss",
    "content": "/* Element Chalk Variables */\n@use 'sass:math';\n@use 'sass:map';\n@use '../../mixins/function.scss' as *;\n\n// types\n$types: primary, success, warning, danger, error, info;\n\n// change color\n$colors: () !default;\n$colors: map.deep-merge(\n  (\n    'white': #ffffff,\n    'black': #000000,\n    'primary': (\n      'base': #c72210//#409eff\n    ),\n    'success': (\n      'base': #45b207\n    ),\n    'warning': (\n      'base': #ec8828\n    ),\n    'danger': (\n      'base': #f56c6c\n    ),\n    'error': (\n      'base': #d24934\n    ),\n    'info': (\n      'base': #909399\n    )\n  ),\n  $colors\n);\n\n$color-white: map.get($colors, 'white') !default;\n$color-black: map.get($colors, 'black') !default;\n$color-primary: map.get($colors, 'primary', 'base') !default;\n$color-success: map.get($colors, 'success', 'base') !default;\n$color-warning: map.get($colors, 'warning', 'base') !default;\n$color-danger: map.get($colors, 'danger', 'base') !default;\n$color-error: map.get($colors, 'error', 'base') !default;\n$color-info: map.get($colors, 'info', 'base') !default;\n\n//$colors添加 --el-color-primary-light-7\n@mixin set-color-mix-level($type, $number, $mode: 'light', $mix-color: $color-white) {\n  $colors: map.deep-merge(\n    (\n      $type: (\n        '#{$mode}-#{$number}': mix($mix-color, map.get($colors, $type, 'base'), math.percentage(math.div($number, 10)))\n      )\n    ),\n    $colors\n  ) !global;\n}\n\n// $colors.primary.light-i\n@each $type in $types {\n  @for $i from 1 through 9 {\n    @include set-color-mix-level($type, $i, 'light', $color-white);\n  }\n}\n"
  },
  {
    "path": "src/theme/lighting/index.scss",
    "content": "/*china-red*/\n//element-plus\n//@use \"./element-plus/css-vars\";\n//@use \"./element-plus/var\";\n//@use \"./element-plus/button\";\n//@use \"./element-plus/checkbox\";\n//@use \"./element-plus/redio\";\n//@use \"./element-plus/pagination\";\n//@use \"./element-plus/form\";\n//@use \"./element-plus/table\";\n\n//custom\n@use \"./custom/ct-css-vars\";\n"
  },
  {
    "path": "src/theme/mixins/_var.scss",
    "content": "/*var mixin*/\n@use 'sass:map';\n\n@use 'config';\n@use 'function' as *;\n\n// set css var value, because we need translate value to string\n// for example:\n// @include set-css-var-value(('color', 'primary'), red);\n// --el-color: red;\n// --el-$name-: $value;\n@mixin set-css-var-value($name, $value) {\n  #{joinVarName($name)}: #{$value};\n}\n\n@mixin set-css-color-type($colors, $type) {\n  @include set-css-var-value(('color', $type), map.get($colors, $type, 'base'));\n  @each $i in (3, 5, 7, 8, 9) {\n    // --el-color-primary-light-7: #c6e2ff;\n    @include set-css-var-value(('color', $type, 'light', $i), map.get($colors, $type, 'light-#{$i}'));\n  }\n\n  //@include set-css-var-value(\n  //      ('color', $type, 'dark-2'),\n  //    map.get($colors, $type, 'dark-2')\n  //);\n}\n\n//el-$name-$attribute-$value\n@mixin set-component-css-var($name, $variables) {\n  @each $attribute, $value in $variables {\n    @if $attribute == 'default' {\n      #{getCssVarName($name)}: #{$value};\n    } @else {\n      #{getCssVarName($name, $attribute)}: #{$value};\n    }\n  }\n}\n\n// --el-color-error-rgb: 245, 108, 108;\n// --el-color-$type-rgb: 245, 108, 108;\n@mixin set-css-color-rgb($colors, $type) {\n  $color: map.get($colors, $type, 'base');\n  @include set-css-var-value(('color', $type, 'rgb'), #{red($color), green($color), blue($color)});\n}\n\n// generate css var from existing css var\n// for example:\n// @include css-var-from-global(('button', 'text-color'), ('color', $type))\n// --el-button-text-color: var(--el-color-#{$type});\n@mixin css-var-from-global($var, $gVar) {\n  $varName: joinVarName($var);\n  $gVarName: joinVarName($gVar);\n  #{$varName}: var(#{$gVarName});\n}\n"
  },
  {
    "path": "src/theme/mixins/config.scss",
    "content": "$namespace: 'el' !default;\n$common-separator: '-' !default;\n$element-separator: '__' !default;\n$modifier-separator: '--' !default;\n$state-prefix: 'is-' !default;\n"
  },
  {
    "path": "src/theme/mixins/function.scss",
    "content": "@use 'config';\n\n// getCssVarName('button', 'text-color') => '--el-button-text-color'\n@function getCssVarName($args...) {\n  @return joinVarName($args);\n}\n\n// getCssVar('button', 'text-color') => var(--el-button-text-color)\n@function getCssVar($args...) {\n  @return var(#{joinVarName($args)});\n}\n\n@function selectorToString($selector) {\n  $selector: inspect($selector);\n  $selector: str-slice($selector, 2, -2);\n  @return $selector;\n}\n\n@function containsModifier($selector) {\n  $selector: selectorToString($selector);\n\n  @if str-index($selector, config.$modifier-separator) {\n    @return true;\n  } @else {\n    @return false;\n  }\n}\n@function hitAllSpecialNestRule($selector) {\n  @return containsModifier($selector) or containWhenFlag($selector) or containPseudoClass($selector);\n}\n@function containWhenFlag($selector) {\n  $selector: selectorToString($selector);\n\n  @if str-index($selector, '.' + config.$state-prefix) {\n    @return true;\n  } @else {\n    @return false;\n  }\n}\n@function containPseudoClass($selector) {\n  $selector: selectorToString($selector);\n\n  @if str-index($selector, ':') {\n    @return true;\n  } @else {\n    @return false;\n  }\n}\n\n// join var name\n// joinVarName(('button', 'text-color')) => '--el-button-text-color'\n@function joinVarName($list) {\n  $name: '--' + config.$namespace;\n  @each $item in $list {\n    @if $item != '' {\n      $name: $name + '-' + $item;\n    }\n  }\n  @return $name;\n}\n"
  },
  {
    "path": "src/theme/mixins/mixins.scss",
    "content": "//input function\n@use 'function' as *;\n@forward 'function';\n\n@forward 'config';\n@use 'config' as *;\n// el-button{}\n@mixin b($block) {\n  $B: $namespace + '-' + $block !global;\n\n  .#{$B} {\n    @content;\n  }\n}\n@mixin e($element) {\n  $E: $element !global;\n  $selector: &;\n  $currentSelector: '';\n  @each $unit in $element {\n    //el-button__text\n    $currentSelector: #{$currentSelector + '.' + $B + $element-separator + $unit + ','};\n  }\n\n  @if hitAllSpecialNestRule($selector) {\n    @at-root {\n      #{$selector} {\n        #{$currentSelector} {\n          @content;\n        }\n      }\n    }\n  } @else {\n    @at-root {\n      #{$currentSelector} {\n        @content;\n      }\n    }\n  }\n}\n\n@mixin m($modifier) {\n  $selector: &;\n  $currentSelector: '';\n  @each $unit in $modifier {\n    $currentSelector: #{$currentSelector + $selector + $modifier-separator + $unit + ','};\n  }\n\n  @at-root {\n    #{$currentSelector} {\n      @content;\n    }\n  }\n}\n\n@mixin when($state) {\n  @at-root {\n    &.#{$state-prefix + $state} {\n      @content;\n    }\n  }\n}\n"
  },
  {
    "path": "src/theme/utils/change-theme.ts",
    "content": "export const toggleHtmlClass = (className) => {\n  document.querySelectorAll('html')[0].className = className\n}\n"
  },
  {
    "path": "src/theme/utils/index.ts",
    "content": "export * from './change-theme'\n"
  },
  {
    "path": "src/utils/axios-req.ts",
    "content": "import axios from 'axios'\nimport { ElLoading, ElMessage, ElMessageBox } from 'element-plus'\nimport { useBasicStore } from '@/store/basic'\n\n//使用axios.create()创建一个axios请求实例\nconst service = axios.create()\nlet loadingInstance: any = null //loading实例\nlet tempReqUrlSave = ''\nlet authorTipDoor = true\n\nconst noAuthDill = () => {\n  authorTipDoor = false\n  ElMessageBox.confirm('请重新登录', {\n    confirmButtonText: '重新登录',\n    closeOnClickModal: false,\n    showCancelButton: false,\n    showClose: false,\n    type: 'warning'\n  }).then(() => {\n    useBasicStore().resetStateAndToLogin()\n    authorTipDoor = true\n  })\n}\n\n//请求前拦截\nservice.interceptors.request.use(\n  (req: any) => {\n    const { token, axiosPromiseArr }: any = useBasicStore()\n    //axiosPromiseArr收集请求地址,用于取消请求\n    req.cancelToken = new axios.CancelToken((cancel) => {\n      tempReqUrlSave = req.url\n      axiosPromiseArr.push({\n        url: req.url,\n        cancel\n      })\n    })\n\n    //设置token到header\n    if (token) req.headers['Authorization'] = token\n    //如果req.method给get 请求参数设置为 ?name=xxx\n    if ('get'.includes(req.method?.toLowerCase()) && !req.params) req.params = req.data\n\n    //req loading\n    // @ts-ignore\n    if (req.reqLoading ?? true) {\n      loadingInstance = ElLoading.service({\n        lock: true,\n        fullscreen: true,\n        // spinner: 'CircleCheck',\n        text: '数据载入中...',\n        background: 'rgba(0, 0, 0, 0.1)'\n      })\n    }\n    return req\n  },\n  (err) => {\n    //发送请求失败\n    Promise.reject(err)\n  }\n)\n//请求后拦截\nservice.interceptors.response.use(\n  (res: any) => {\n    //取消请求\n    useBasicStore().remotePromiseArrByReqUrl(tempReqUrlSave)\n    if (loadingInstance) {\n      loadingInstance && loadingInstance.close()\n    }\n    //download file\n    if (res.data?.type?.includes(\"sheet\")) {\n      return res\n    }\n    const { code, msg } = res.data\n    const successCode = [0,200,20000]\n    const noAuthCode = [401,403]\n    if (successCode.includes(code)) {\n      return res.data\n    } else {\n      //authorTipDoor 防止多个请求 多次alter\n      if (authorTipDoor) {\n        if (noAuthCode.includes(code)) {\n          noAuthDill()\n        } else {\n          // @ts-ignore\n          if (!res.config?.isNotTipErrorMsg) {\n            ElMessage.error({\n              message: msg,\n              duration: 2 * 1000\n            })\n          } else {\n            return res\n          }\n          return Promise.reject(msg)\n        }\n      }\n    }\n  },\n  //响应报错\n  (err) => {\n    //取消请求\n    useBasicStore().remotePromiseArrByReqUrl(tempReqUrlSave)\n    if (loadingInstance) {\n      loadingInstance && loadingInstance.close()\n    }\n    ElMessage.error({\n      message: err,\n      duration: 2 * 1000\n    })\n    return Promise.reject(err)\n  }\n)\n//导出service实例给页面调用 , config->页面的配置\nexport default function axiosReq(config) {\n  return service({\n    baseURL: import.meta.env.VITE_APP_BASE_URL,\n    timeout: 8000,\n    ...config\n  })\n}\n"
  },
  {
    "path": "src/utils/bus.ts",
    "content": "//bus even\nimport mitt from 'mitt'\nexport default mitt()\n"
  },
  {
    "path": "src/utils/common-util.ts",
    "content": "export default {\n  getWeek() {\n    return `星期${'日一二三四五六'.charAt(new Date().getDay())}`\n    // this.showDate=this.$momentMini(new Date()).format('YYYY年MM月DD日，')+str\n  },\n  /* 表单验证*/\n  // 匹配手机\n  mobilePhone(str) {\n    const reg = /^0?1[0-9]{10}$/\n    return reg.test(str)\n  },\n  /*\n   * 传入一串num四个 一个空格\n   * */\n  toSplitNumFor(num, numToSpace) {\n    return num.replace(/(.{4})/g, '$1 ')\n  },\n  // 匹配银行卡号\n  bankCardNo(str) {\n    const reg = /^\\d{15,20}$/\n    return reg.test(str)\n  },\n  // 邮箱\n  regEmail(str) {\n    const reg = /^([a-zA-Z]|[0-9])(\\w|-)+@[a-zA-Z0-9]+\\.([a-zA-Z]{2,4})$/\n    return reg.test(str)\n  },\n  // 省份证\n  idCardNumber(str) {\n    const reg = /(^\\d{15}$)|(^\\d{18}$)|(^\\d{17}(\\d|X|x)$)/\n    return reg.test(str)\n  },\n  /* 常用数组操作*/\n  /*\n   * 删除数组中的指定元素\n   * arrItem 数组的index下标\n   * return 删除后的数组\n   * */\n  deleteArrItem(arr, arrItem) {\n    arr.splice(arr.indexOf(arrItem), 1)\n  },\n  /*\n   *  数组去重\n   *  arr：要去重的数组\n   *  return 去重后的数组\n   * */\n  arrToRepeat(arr) {\n    return arr.filter((ele, index, thisArr) => {\n      // 因为indexOf返回元素出现的第一个index位置,如果有重复的话那么他的位置永远是第一次出现的index,这就与他本身的index不相符,则删掉.\n      return thisArr.indexOf(ele) === index\n    })\n  },\n  /*\n   * 数组去重\n   * seriesArr: 数组\n   * return 去重后的数组\n   * */\n  deRepeatArr(seriesArr) {\n    return [...new Set(seriesArr)]\n  },\n  /*\n   * 根据arrObj 删除arrObj2   根据arrObj objKey查找删除\n   * arrObj: 数组对象\n   * arrObj2: 要被删除的对象\n   * objKey： arrObj中对象的某一个key名称\n   * return: arrObj2删除过后的数组\n   * */\n  byArrObjDeleteArrObj2(arrObj, arrObj2, objKey) {\n    arrObj\n      .map((value) => {\n        return value[objKey]\n      })\n      .forEach((value2) => {\n        arrObj2.splice(\n          arrObj2.findIndex((item) => item[objKey] === value2),\n          1\n        )\n      })\n    return arrObj2\n  },\n  /*\n   * 删除arrObj某一项 根据objKey中的key的值等于value的值\n   * arrObj: 数组对象\n   * objKey：arrObj中对象的某一个key名称\n   * return: arrObj删除过后的数组\n   * */\n  deleteArrObjByKey(arrObj, objKey, value) {\n    //foreach splice\n    //for substring  slice 不改变原数组\n    arrObj.splice(\n      arrObj.findIndex((item) => item[objKey] === value),\n      1\n    )\n    return arrObj\n  },\n  /*\n   * 查找arrObj某一项 根据objKey中的值\n   * arrObj: 数组对象\n   * objKey：arrObj中对象的某一个key名称\n   * return: arrObj查找 过后的数组\n   * */\n  findArrObjByKey(arrObj, objKey, value) {\n    return arrObj[arrObj.findIndex((item) => item[objKey] == value)]\n  },\n  /*\n   * 根据arrObj 筛选arrObj2   根据arrObj objKey值查找\n   * arrObj: 数组对象\n   * arrObj2: 要被删除的对象\n   * objKey： arrObj中对象的某一个key名称\n   * return: arrObj2删除过后的数组\n   * */\n  byArrObjFindArrObj2(arrObj, arrObj2, objKey) {\n    const arrObj3: Array<any> = []\n    arrObj\n      .map((value) => {\n        return value[objKey]\n      })\n      .forEach((value2) => {\n        const arrIndex = arrObj2.findIndex((item) => item[objKey] === value2)\n        if (arrIndex !== -1) {\n          arrObj3.push(arrObj2[arrIndex])\n        }\n      })\n    return arrObj3\n  }\n}\n"
  },
  {
    "path": "src/views/basic-demo/hook/index.vue",
    "content": "<template>\n  <div>\n    <div class=\"font-bold mb-20px\">引入use-common.ts中的copyValueToClipboard</div>\n    <el-button @click=\"hookExample\">执行hook方法</el-button>\n  </div>\n</template>\n\n<script setup lang=\"ts\">\n//由于使用了 AutoImport 插件 可以直接引入hooks里的api\n//引入use-common.ts中的copyValueToClipboard\nconst hookExample = () => {\n  copyValueToClipboard('执行hook方法')\n}\n</script>\n"
  },
  {
    "path": "src/views/basic-demo/keep-alive/index.vue",
    "content": "<template>\n  <div class=\"scroll-y\">\n    <div class=\"font-bold mb-10px\">Second Page KeepAlive Demo</div>\n\n    <el-form ref=\"refsearchForm\" :inline=\"true\" class=\"mt-2\">\n      <el-form-item label-width=\"0px\" label=\"\" prop=\"errorLog\" label-position=\"left\">\n        <el-input v-model=\"searchForm.name\" class=\"w-150px\" placeholder=\"input to test keepAlive\" />\n      </el-form-item>\n      <el-form-item label-width=\"0px\" label=\"\" prop=\"pageUrl\" label-position=\"left\">\n        <el-input v-model=\"searchForm.age\" class=\"w-150px\" placeholder=\"input to test keepAlive\" />\n      </el-form-item>\n    </el-form>\n    <el-button type=\"primary\" @click=\"routerDemoF\">to SecondChild.vue</el-button>\n  </div>\n</template>\n<script setup lang=\"ts\" name=\"KeepAliveGroup\">\n//使用keep-alive 1.设置name（必须） 2.在路由配置处设置cachePage：即可缓存\nconst searchForm = reactive({\n  name: '',\n  age: ''\n})\nconst testRef = ref(1)\n//赋值\ntestRef.value = 2\nconsole.log(testRef.value)\nonActivated(() => {\n  console.log('onActivated')\n})\nonDeactivated(() => {\n  console.log('onDeactivated')\n})\n\nconst routerDemoF = () => {\n  //推荐路由跳转根据router的name,这样在你修改路径时，只要不修改name，就没有影响。\n  //推荐传递的是query参数，好处是刷新时可以回显，传入的obj对象会反序列化。\n  routerPush('SecondChild', { name: 'SecondKeepAlive' })\n}\n</script>\n"
  },
  {
    "path": "src/views/basic-demo/keep-alive/second-child.vue",
    "content": "<template>\n  <div class=\"scroll-y\">\n    <div class=\"font-bold mb-20px\">second-level.vue</div>\n    <el-form ref=\"refsearchForm\" :inline=\"true\" class=\"mt-2\">\n      <el-form-item label-width=\"0px\" label=\"\" prop=\"errorLog\" label-position=\"left\">\n        <el-input v-model=\"searchForm.name\" class=\"w-150px\" placeholder=\"input to test keepAlive\" />\n      </el-form-item>\n      <el-form-item label-width=\"0px\" label=\"\" prop=\"pageUrl\" label-position=\"left\">\n        <el-input v-model=\"searchForm.age\" class=\"w-150px\" placeholder=\"demo1\" />\n      </el-form-item>\n    </el-form>\n    <el-button type=\"primary\" @click=\"routerDemoS\">to ThirdChild.vue</el-button>\n    <el-button type=\"primary\" @click=\"backClick\">返回</el-button>\n  </div>\n</template>\n<script setup lang=\"ts\" name=\"SecondChild\">\nconst searchForm = reactive({\n  name: '',\n  age: ''\n})\nonMounted(() => {\n  //get page pass url data\n  console.log(getQueryParam())\n})\nconst backClick = () => {\n  routerBack()\n}\nconst routerDemoS = () => {\n  routerPush('ThirdChild', { name: 'SecondChild' })\n}\n</script>\n\n<style scoped lang=\"scss\"></style>\n"
  },
  {
    "path": "src/views/basic-demo/keep-alive/second-keep-alive.vue",
    "content": "<template>\n  <div class=\"scroll-y\">\n    <div class=\"font-bold mb-10px\">Second Page KeepAlive Demo</div>\n\n    <el-form ref=\"refsearchForm\" :inline=\"true\" class=\"mt-2\">\n      <el-form-item label-width=\"0px\" label=\"\" prop=\"errorLog\" label-position=\"left\">\n        <el-input v-model=\"searchForm.name\" class=\"w-150px\" placeholder=\"input to test keepAlive\" />\n      </el-form-item>\n      <el-form-item label-width=\"0px\" label=\"\" prop=\"pageUrl\" label-position=\"left\">\n        <el-input v-model=\"searchForm.age\" class=\"w-150px\" placeholder=\"input to test keepAlive\" />\n      </el-form-item>\n    </el-form>\n    <el-button type=\"primary\" @click=\"routerDemoF\">to SecondChild.vue</el-button>\n  </div>\n</template>\n<script setup lang=\"ts\" name=\"SecondKeepAlive\">\n//使用keep-alive 1.设置name（必须） 2.在路由配置处设置cachePage：即可缓存\nconst searchForm = reactive({\n  name: '',\n  age: ''\n})\nconst testRef = ref(1)\n//赋值\ntestRef.value = 2\nconsole.log(testRef.value)\nonActivated(() => {\n  console.log('onActivated')\n})\nonDeactivated(() => {\n  console.log('onDeactivated')\n})\n\nconst routerDemoF = () => {\n  //推荐路由跳转根据router的name,这样在你修改路径时，只要不修改name，就没有影响。\n  //推荐传递的是query参数，好处是刷新时可以回显，传入的obj对象会反序列化。\n  routerPush('SecondChild', { name: 'SecondKeepAlive' })\n}\n</script>\n"
  },
  {
    "path": "src/views/basic-demo/keep-alive/tab-keep-alive.vue",
    "content": "<template>\n  <div class=\"scroll-y\">\n    <div class=\"font-bold mb-10px\">Tab KeepAlive Demo</div>\n    <el-input v-model=\"searchForm.pageUrl\" style=\"width: 200px\" placeholder=\"input to test TabKeepAlive\" />\n  </div>\n</template>\n<script setup lang=\"ts\" name=\"TabKeepAlive\">\nconst searchForm = reactive({\n  pageUrl: ''\n})\nconst testRef = ref(1)\ntestRef.value = 2\nonActivated(() => {\n  console.log('onActivated')\n})\nonDeactivated(() => {\n  console.log('onDeactivated')\n})\n</script>\n"
  },
  {
    "path": "src/views/basic-demo/keep-alive/third-child.vue",
    "content": "<template>\n  <div class=\"scroll-y\">\n    <h2 class=\"font-bold mb-10px\">third-level.vue</h2>\n    <el-form ref=\"refsearchForm\" :inline=\"true\" class=\"mt-2\">\n      <el-form-item label-width=\"0px\" label=\"\" prop=\"errorLog\" label-position=\"left\">\n        <el-input v-model=\"searchForm.errorLog\" class=\"w-150px\" placeholder=\"input to test keepAlive\" />\n      </el-form-item>\n      <el-form-item label-width=\"0px\" label=\"\" prop=\"pageUrl\" label-position=\"left\">\n        <el-input v-model=\"searchForm.pageUrl\" class=\"w-150px\" placeholder=\"input to test keepAlive\" />\n      </el-form-item>\n    </el-form>\n    <el-button type=\"primary\" @click=\"backClick\">返回</el-button>\n  </div>\n</template>\n\n<script setup name=\"ThirdChild\">\nconst searchForm = reactive({\n  name: '',\n  age: ''\n})\nconst backClick = () => {\n  routerBack()\n}\nonMounted(() => {\n  //get page pass url data\n  console.log(getQueryParam())\n})\n</script>\n\n<style scoped lang=\"scss\"></style>\n"
  },
  {
    "path": "src/views/basic-demo/mock/index.vue",
    "content": "<template>\n  <div class=\"scroll-y\">\n    <div class=\"font-bold mb-20px\">mock使用示例</div>\n    <el-button type=\"primary\" @click=\"listReq\">点击发送mock请求</el-button>\n  </div>\n</template>\n\n<script setup lang=\"ts\">\nimport axios from 'axios'\nconst listReq = () => {\n  axios.post('/mock/login').then(({ data }) => {\n    elMessage(data)\n  })\n}\n</script>\n\n<style scoped lang=\"scss\"></style>\n"
  },
  {
    "path": "src/views/basic-demo/parent-children/Children.vue",
    "content": "<template>\n  <div>\n    <div class=\"font-bold mb-10px mt-20px\">call father method</div>\n    <el-button @click=\"emitFather\">emitFather</el-button>\n    <el-button @click=\"getFatherMethod\">getFatherMethod</el-button>\n    <SubChildren />\n  </div>\n\n  <div class=\"mt-20px font-bold mb-10px\">slot using</div>\n  <!-- 默认插槽 -->\n  <slot>\n    <!-- slot内为后备内容 -->\n    <h3>没传内容</h3>\n  </slot>\n  <!-- 具名插槽 -->\n  <slot name=\"header\">\n    <h3>没传header插槽</h3>\n  </slot>\n  <!-- 作用域插槽 -->\n  <slot name=\"footer\" test-props=\"子组件作用域传的值\">\n    <h3>没传footer插槽</h3>\n  </slot>\n\n  <div class=\"mt-20px mb-10px font-bold\">v-model sync using</div>\n  <div>{{ childrenTitle }}</div>\n  <el-button @click=\"changeParentValue\">changeParentValue</el-button>\n</template>\n\n<script setup lang=\"ts\">\nimport SubChildren from './SubChildren.vue'\nconst props = defineProps({\n  fatherName: {\n    require: true,\n    default: '',\n    type: String\n  },\n  childrenTitle: {\n    require: true,\n    default: '',\n    type: String\n  }\n})\nconst state = reactive({\n  name: 'Children'\n})\n//导出给refs使用\nconst childRef = ref('childRef')\nconst childMethod = () => {\n  return 'childMethod'\n}\n\nconst vm: any = getCurrentInstance()?.proxy\nconst getFatherMethod = () => {\n  vm?.$parent?.fartherMethod()\n}\n//emit\n// 定义emit事件\nconst emit = defineEmits(['emitParent', 'update:childrenTitle'])\nconst emitFather = () => {\n  emit('emitParent', { val: '子组件传递的信息' })\n}\nonMounted(() => {\n  console.log('得到父元素的prop', props.fatherName)\n})\n\n//v-model sync\nonMounted(() => {\n  console.log(`this is v-model parent data:${props.childrenTitle}`)\n})\nconst changeParentValue = () => {\n  emit('update:childrenTitle', 'update it childrenTitle')\n}\ndefineExpose({ childRef, childMethod })\n//export to page for use\nconst { name } = toRefs(state)\n</script>\n"
  },
  {
    "path": "src/views/basic-demo/parent-children/SubChildren.vue",
    "content": "<template>\n  <div class=\"font-bold mt-20px mb-10px\">provide and inject using</div>\n  <div>{{ title }}</div>\n\n  <div class=\"mt-20px font-bold mb-10px\">Teleport Using</div>\n  <!--\n     teleport container\n     attention: the container must exist when the teleport render\n     -->\n  <div id=\"modal-container\" />\n  <!--  to container-->\n  <teleport v-if=\"modalOpen\" to=\"#modal-container\">\n    <div class=\"modal\">\n      <div>\n        to container\n        <el-button @click=\"modalOpen = false\">Close</el-button>\n      </div>\n    </div>\n  </teleport>\n  <!--  to body-->\n  <!--  <teleport v-if=\"modalOpen\" to=\"body\">-->\n  <!--    <div>to body</div>-->\n  <!--  </teleport>-->\n  <el-button @click=\"showModalOpen\">showModalOpen</el-button>\n</template>\n\n<script setup lang=\"ts\">\n//provide and inject using\nconst title = inject('title')\nconst modalOpen = ref(false)\nconst showModalOpen = () => {\n  modalOpen.value = true\n}\n</script>\n"
  },
  {
    "path": "src/views/basic-demo/parent-children/index.vue",
    "content": "<template>\n  <div class=\"scroll-y\">\n    <div class=\"font-bold mb-10px\">call child method</div>\n    <el-button @click=\"childMethod\">call childMethod</el-button>\n    <!--v-model sync -->\n    <Children ref=\"refChildren\" v-model:childrenTitle=\"parentTitle\" father-name=\"Vue3Template\" @emitParent=\"emitParent\">\n      <!--默认插槽 v-slot -->\n      <template #default>\n        <div>默认插槽</div>\n      </template>\n      <!--具名插槽// v-slot:header -->\n      <template #header>\n        <div>具名插槽</div>\n      </template>\n      <!--作用域插槽  //v-slot:footer-->\n      <template #footer=\"{ testProps }\">\n        {{ testProps }}\n      </template>\n    </Children>\n  </div>\n</template>\n\n<script setup lang=\"ts\">\nimport Children from './Children.vue'\nconst refChildren = ref()\nonMounted(() => {\n  /*获取子元素方法*/\n  console.log(refChildren.value)\n})\nconst childMethod = () => {\n  console.log(refChildren.value.childMethod())\n  console.log(refChildren.value.childRef)\n}\nconst emitParent = (data) => {\n  console.log('得到子组件的信息111', data)\n}\nconst fartherMethod = () => {\n  console.log('fartherMethod')\n}\n//provide\nprovide('title', 'provide value')\n\n//v-model sync\nconst parentTitle = ref('parentTitle')\n\nwatch(\n  () => parentTitle.value,\n  (oldValue, newValue) => {\n    console.log('触发parent更新了', oldValue, newValue)\n  },\n  { immediate: true }\n)\ndefineExpose({ fartherMethod })\n</script>\n"
  },
  {
    "path": "src/views/basic-demo/pinia/index.vue",
    "content": "<template>\n  <div>\n    <div class=\"font-bold mb-20px\">由于使用了 AutoImport 插件 可以直接引入pinia里的api</div>\n    <el-button @click=\"sidebar.opened = !sidebar.opened\">switch sidebar.opened</el-button>\n  </div>\n</template>\n\n<script setup lang=\"ts\">\n//由于使用了 AutoImport 插件 可以直接引入pinia里的api\n//storeToRefs:引入的store属性具备响应式\nconst { sidebar } = storeToRefs(useBasicStore())\n</script>\n\n<style scoped lang=\"scss\"></style>\n"
  },
  {
    "path": "src/views/basic-demo/svg-icon/index.vue",
    "content": "<template>\n  <div class=\"scroll-y\">\n    <div class=\"font-bold mb-20px\">svg-icon使用示例</div>\n    <svg-icon icon-class=\"sidebar-logo\" class=\"svg-class\" />\n  </div>\n</template>\n\n<script setup lang=\"ts\">\n//配置了 Components.dirs自动扫描组件，无需引入\n// import SvgIcon from '@/icons/SvgIcon.vue'\n</script>\n\n<style scoped lang=\"scss\">\n.svg-class {\n  font-size: 100px;\n  color: var(--sidebar-logo-color);\n}\n</style>\n"
  },
  {
    "path": "src/views/basic-demo/vue3-template/Vue3Template.vue",
    "content": "<template>\n  <div>vue3推荐模板可以集成在你们的vscode或webstorm中，有助于快速开发</div>\n</template>\n\n<script setup>\n// 获取store和router\n\nconst props = defineProps({\n  name: {\n    require: true,\n    default: 'fai',\n    type: String\n  }\n})\nconst state = reactive({\n  levelList: null\n})\n\nconst routes = computed(() => 'value')\nwatch(\n  () => props.name,\n  (oldValue, newValue) => {},\n  { immediate: true }\n)\n\nconst router = useRouter()\nonMounted(() => {\n  console.log('页面挂载了')\n})\nconst helloFunc = () => {\n  console.log('helloFunc')\n}\n// 导出给父元素使用\ndefineExpose({ helloFunc })\n// 导出属性到页面中使用\nconst { levelList } = toRefs(state)\n</script>\n\n<style scoped lang=\"scss\"></style>\n"
  },
  {
    "path": "src/views/basic-demo/worker/index.vue",
    "content": "<template>\n  <div>\n    <div>the recommend using way of worker</div>\n    <div>计算结果：{{ showPageRef }}</div>\n    <el-icon v-if=\"!showPageRef\" class=\"is-loading\">\n      <Loading />\n    </el-icon>\n  </div>\n</template>\n<script setup lang=\"ts\">\n/*推荐worker使用方式*/\n// 方式，函数直接转换\nconst workerCode = () => {\n  onmessage = (e) => {\n    console.time('加载时间')\n    console.log(`接收到主线程的信息${e.data}`)\n    //处理复杂的js逻辑\n    let countNum = 0\n    for (let i = 0; i < e.data; i++) {\n      countNum = i + countNum\n    }\n    //处理完毕返回主线程\n    console.log('子线程数据处理完毕返回主线程')\n    console.timeEnd('加载时间')\n    postMessage(countNum)\n  }\n}\n\n//change func to url for worker using\nconst changeFuncToUrl = (func) => {\n  const workBlob = new Blob([`(${func.toString()})()`]) // 把函数转成一个自执行函数\n  const url = URL.createObjectURL(workBlob)\n  return new Worker(url)\n}\n\n//主线程逻辑\nconst worker = changeFuncToUrl(workerCode)\nworker.postMessage(30000000)\nconst showPageRef = ref()\nworker.onmessage = (e) => {\n  console.log(`主进程收到了子进程发出的信息：${e.data}`)\n  showPageRef.value = e.data\n  //停止线程（注:用完后一定要停止）\n  worker.terminate()\n}\n</script>\n"
  },
  {
    "path": "src/views/dashboard/index.vue",
    "content": "<template>\n  <div class=\"scroll-y\">\n    <div v-lang class=\"mt-10px mb-10px font-bold\">switch theme</div>\n    <el-button @click=\"setTheme('base-theme')\">base-theme(default)</el-button>\n    <el-button @click=\"setTheme('lighting-theme')\">lighting-theme</el-button>\n    <el-button @click=\"setTheme('china-red')\">china-red(default)</el-button>\n    <el-button @click=\"setTheme('dark')\">dark-theme</el-button>\n\n    <div v-lang class=\"mt-10px mb-10px font-bold\">switch size</div>\n    <el-button @click=\"setSize('large')\">large</el-button>\n    <el-button @click=\"setSize('default')\">default</el-button>\n    <el-button @click=\"setSize('small')\">small</el-button>\n\n    <div v-lang class=\"mt-10px mb-10px font-bold\">switch language</div>\n    <el-button @click=\"changeLanguage('en')\">en</el-button>\n    <el-button @click=\"changeLanguage('zh')\">zh</el-button>\n\n    <!--example components -->\n    <div v-lang class=\"mb-10px font-bold mt-20px\">Button Group</div>\n    <el-button type=\"primary\" @click=\"count++\">count is: {{ count }}</el-button>\n    <el-button type=\"success\" @click=\"count++\">count is: {{ count }}</el-button>\n    <el-button type=\"warning\" @click=\"count++\">count is: {{ count }}</el-button>\n    <el-button type=\"danger\" @click=\"count++\">count is: {{ count }}</el-button>\n    <el-button type=\"info\" @click=\"count++\">count is: {{ count }}</el-button>\n\n    <div v-lang class=\"mt-30px font-bold mb-10px\">unocss using</div>\n    <div class=\"mb-40px w-900px h-10px text-16px\">\n      <div>\n        you can look\n        <el-link class=\"text-red\" href=\"https://uno.antfu.me/\" target=\"_blank\">https://uno.antfu.me/</el-link>\n        to search you need such as \"margin-left:10px\" and then get the sortcut(ml-10px)\n      </div>\n    </div>\n\n    <div v-lang class=\"mt-30px font-bold mb-10px\">global var</div>\n    {{ showObj }}\n  </div>\n</template>\n<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { useRoute } from 'vue-router'\nimport { useConfigStore } from '@/store/config'\n\nconst { setTheme, theme, setSize, size, setLanguage } = useConfigStore()\nconst route = useRoute()\nconst changeLanguage = (langParam) => {\n  setLanguage(langParam, route.meta?.title)\n}\nconst count = ref(0)\nconst showObj = ref(GLOBAL_VAR)\n</script>\n"
  },
  {
    "path": "src/views/error-page/401.vue",
    "content": "<template>\n  <div class=\"errPage-container\">\n    <el-button icon=\"el-icon-arrow-left\" class=\"pan-back-btn\" @click=\"back\">返回</el-button>\n    <el-row>\n      <el-col :span=\"12\">\n        <h1 class=\"text-jumbo text-ginormous\">Oops!</h1>\n        gif来源\n        <a href=\"https://zh.airbnb.com/\" target=\"_blank\">airbnb</a>\n        页面\n        <h2>你没有权限去该页面</h2>\n        <h6>如有不满请联系你领导</h6>\n        <ul class=\"list-unstyled\">\n          <li>或者你可以去:</li>\n          <li class=\"link-type\">\n            <router-link to=\"/dashboard\">回首页</router-link>\n          </li>\n          <li class=\"link-type\">\n            <a href=\"https://www.taobao.com/\">随便看看</a>\n          </li>\n          <li><a href=\"#\" @click.prevent=\"dialogVisible = true\">点我看图</a></li>\n        </ul>\n      </el-col>\n      <el-col :span=\"12\">\n        <img :src=\"errGif\" width=\"313\" height=\"428\" alt=\"Girl has dropped her ice cream.\" />\n      </el-col>\n    </el-row>\n    <el-dialog v-model=\"dialogVisible\" title=\"随便看\">\n      <img :src=\"ewizardClap\" class=\"pan-img\" />\n    </el-dialog>\n  </div>\n</template>\n\n<script setup>\nimport errGif from '@/assets/401_images/401.gif'\n\nconst state = reactive({\n  errGif: `${errGif  }?${  Date.now()}`,\n  ewizardClap: 'https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646',\n  dialogVisible: false\n})\n\nconst route = useRoute()\nconst router = useRouter()\nconst back = () => {\n  if (route.query.noGoBack) {\n    router.push({ path: '/dashboard' })\n  } else {\n    router.go(-1)\n  }\n}\n//导出属性到页面中使用\nconst { ewizardClap, dialogVisible } = toRefs(state)\n</script>\n\n<style lang=\"scss\" scoped>\n.errPage-container {\n  width: 800px;\n  max-width: 100%;\n  margin: 100px auto;\n  .pan-back-btn {\n    background: #008489;\n    color: #fff;\n    border: none !important;\n  }\n  .pan-gif {\n    margin: 0 auto;\n    display: block;\n  }\n  .pan-img {\n    display: block;\n    margin: 0 auto;\n    width: 100%;\n  }\n  .text-jumbo {\n    font-size: 60px;\n    font-weight: 700;\n    color: #484848;\n  }\n  .list-unstyled {\n    font-size: 14px;\n    li {\n      padding-bottom: 5px;\n    }\n    a {\n      color: #008489;\n      text-decoration: none;\n      &:hover {\n        text-decoration: underline;\n      }\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "src/views/error-page/404.vue",
    "content": "<template>\n  <div class=\"wscn-http404-container\">\n    <div class=\"wscn-http404\">\n      <div class=\"pic-404\">\n        <img class=\"pic-404__parent\" src=\"@/assets/404_images/404.png\" alt=\"404\" />\n        <img class=\"pic-404__child left\" src=\"@/assets/404_images/404_cloud.png\" alt=\"404\" />\n        <img class=\"pic-404__child mid\" src=\"@/assets/404_images/404_cloud.png\" alt=\"404\" />\n        <img class=\"pic-404__child right\" src=\"@/assets/404_images/404_cloud.png\" alt=\"404\" />\n      </div>\n      <div class=\"bullshit\">\n        <div class=\"bullshit__oops\">OOPS!</div>\n        <div class=\"bullshit__info\">\n          All rights reserved\n          <a style=\"color: #20a0ff\" href=\"https://wallstreetcn.com\" target=\"_blank\">wallstreetcn</a>\n        </div>\n        <div class=\"bullshit__headline\">{{ message }}</div>\n        <div class=\"bullshit__info\">\n          Please check that the URL you entered is correct, or click the button below to return to the homepage.\n        </div>\n        <a href=\"\" class=\"bullshit__return-home\">Back to home</a>\n      </div>\n    </div>\n  </div>\n</template>\n\n<script setup>\nconst message = computed(() => {\n  return 'The webmaster said that you can not enter this page...'\n})\n</script>\n\n<style lang=\"scss\" scoped>\n.wscn-http404-container {\n  transform: translate(-50%, -50%);\n  position: absolute;\n  top: 40%;\n  left: 50%;\n}\n.wscn-http404 {\n  position: relative;\n  width: 1200px;\n  padding: 0 50px;\n  overflow: hidden;\n  .pic-404 {\n    position: relative;\n    float: left;\n    width: 600px;\n    overflow: hidden;\n    &__parent {\n      width: 100%;\n    }\n    &__child {\n      position: absolute;\n      &.left {\n        width: 80px;\n        top: 17px;\n        left: 220px;\n        opacity: 0;\n        animation-name: cloudLeft;\n        animation-duration: 2s;\n        animation-timing-function: linear;\n        animation-fill-mode: forwards;\n        animation-delay: 1s;\n      }\n      &.mid {\n        width: 46px;\n        top: 10px;\n        left: 420px;\n        opacity: 0;\n        animation-name: cloudMid;\n        animation-duration: 2s;\n        animation-timing-function: linear;\n        animation-fill-mode: forwards;\n        animation-delay: 1.2s;\n      }\n      &.right {\n        width: 62px;\n        top: 100px;\n        left: 500px;\n        opacity: 0;\n        animation-name: cloudRight;\n        animation-duration: 2s;\n        animation-timing-function: linear;\n        animation-fill-mode: forwards;\n        animation-delay: 1s;\n      }\n      @keyframes cloudLeft {\n        0% {\n          top: 17px;\n          left: 220px;\n          opacity: 0;\n        }\n        20% {\n          top: 33px;\n          left: 188px;\n          opacity: 1;\n        }\n        80% {\n          top: 81px;\n          left: 92px;\n          opacity: 1;\n        }\n        100% {\n          top: 97px;\n          left: 60px;\n          opacity: 0;\n        }\n      }\n      @keyframes cloudMid {\n        0% {\n          top: 10px;\n          left: 420px;\n          opacity: 0;\n        }\n        20% {\n          top: 40px;\n          left: 360px;\n          opacity: 1;\n        }\n        70% {\n          top: 130px;\n          left: 180px;\n          opacity: 1;\n        }\n        100% {\n          top: 160px;\n          left: 120px;\n          opacity: 0;\n        }\n      }\n      @keyframes cloudRight {\n        0% {\n          top: 100px;\n          left: 500px;\n          opacity: 0;\n        }\n        20% {\n          top: 120px;\n          left: 460px;\n          opacity: 1;\n        }\n        80% {\n          top: 180px;\n          left: 340px;\n          opacity: 1;\n        }\n        100% {\n          top: 200px;\n          left: 300px;\n          opacity: 0;\n        }\n      }\n    }\n  }\n  .bullshit {\n    position: relative;\n    float: left;\n    width: 300px;\n    padding: 30px 0;\n    overflow: hidden;\n    &__oops {\n      font-size: 32px;\n      font-weight: bold;\n      line-height: 40px;\n      color: #1482f0;\n      opacity: 0;\n      margin-bottom: 20px;\n      animation-name: slideUp;\n      animation-duration: 0.5s;\n      animation-fill-mode: forwards;\n    }\n    &__headline {\n      font-size: 20px;\n      line-height: 24px;\n      color: #222;\n      font-weight: bold;\n      opacity: 0;\n      margin-bottom: 10px;\n      animation-name: slideUp;\n      animation-duration: 0.5s;\n      animation-delay: 0.1s;\n      animation-fill-mode: forwards;\n    }\n    &__info {\n      font-size: 13px;\n      line-height: 21px;\n      color: grey;\n      opacity: 0;\n      margin-bottom: 30px;\n      animation-name: slideUp;\n      animation-duration: 0.5s;\n      animation-delay: 0.2s;\n      animation-fill-mode: forwards;\n    }\n    &__return-home {\n      display: block;\n      float: left;\n      width: 110px;\n      height: 36px;\n      background: #1482f0;\n      border-radius: 100px;\n      text-align: center;\n      color: #ffffff;\n      opacity: 0;\n      font-size: 14px;\n      line-height: 36px;\n      cursor: pointer;\n      animation-name: slideUp;\n      animation-duration: 0.5s;\n      animation-delay: 0.3s;\n      animation-fill-mode: forwards;\n    }\n    @keyframes slideUp {\n      0% {\n        transform: translateY(60px);\n        opacity: 0;\n      }\n      100% {\n        transform: translateY(0);\n        opacity: 1;\n      }\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "src/views/login/index.vue",
    "content": "<template>\n  <div class=\"login-container columnCC\">\n    <el-form ref=\"refLoginForm\" class=\"login-form\" :model=\"subForm\" :rules=\"formRules\">\n      <div class=\"title-container\">\n        <h3 class=\"title text-center\">{{ settings.title }}</h3>\n      </div>\n      <el-form-item prop=\"keyword\" :rules=\"formRules.isNotNull('usename不能为空')\">\n        <div class=\"rowSC\">\n          <span class=\"svg-container\">\n            <svg-icon icon-class=\"user\" />\n          </span>\n          <el-input v-model=\"subForm.keyword\" placeholder=\"用户名(admin)\" />\n          <!--占位-->\n          <div class=\"show-pwd\" />\n        </div>\n      </el-form-item>\n      <!--<el-form-item prop=\"password\" :rules=\"formRules.passwordValid\">-->\n      <el-form-item prop=\"password\" :rules=\"formRules.isNotNull('密码不能为空')\">\n        <div class=\"rowSC flex-1\">\n          <span class=\"svg-container\">\n            <svg-icon icon-class=\"password\" />\n          </span>\n          <el-input\n            :key=\"passwordType\"\n            ref=\"refPassword\"\n            v-model=\"subForm.password\"\n            :type=\"passwordType\"\n            name=\"password\"\n            placeholder=\"password(123456)\"\n            @keyup.enter=\"handleLogin\"\n          />\n          <span class=\"show-pwd\" @click=\"showPwd\">\n            <svg-icon :icon-class=\"passwordType === 'password' ? 'eye' : 'eye-open'\" />\n          </span>\n        </div>\n      </el-form-item>\n      <div class=\"tip-message\">{{ tipMessage }}</div>\n      <el-button :loading=\"subLoading\" type=\"primary\" class=\"login-btn\" size=\"default\" @click.prevent=\"handleLogin\">\n        Login\n      </el-button>\n    </el-form>\n  </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { onMounted, reactive, ref, watch } from 'vue'\nimport { useRoute, useRouter } from 'vue-router'\nimport { useBasicStore } from '@/store/basic'\nimport { elMessage, useElement } from '@/hooks/use-element'\nimport { loginReq } from '@/api/user'\n\n/* listen router change and set the query  */\nconst { settings } = useBasicStore()\n//element valid\nconst formRules = useElement().formRules\n//form\nconst subForm = reactive({\n  keyword: 'panda',\n  password: '123456'\n})\nconst state:any = reactive({\n  otherQuery: {},\n  redirect: \"\"\n})\nconst route = useRoute()\nconst getOtherQuery = (query) => {\n  return Object.keys(query).reduce((acc, cur) => {\n    if (cur !== 'redirect') {\n      acc[cur] = query[cur]\n    }\n    return acc\n  }, {})\n}\nwatch(\n  () => route.query,\n  (query) => {\n    if (query) {\n      state.redirect = query.redirect\n      state.otherQuery = getOtherQuery(query)\n    }\n  },\n  { immediate: true }\n)\n\n/*\n *  login relative\n * */\nconst subLoading = ref(false)\n//tip message\nconst tipMessage = ref()\n//sub form\nconst refLoginForm = ref()\nconst handleLogin = () => {\n  refLoginForm.value.validate((valid) => {\n    subLoading.value = true\n    if (valid) loginFunc()\n  })\n}\nconst router = useRouter()\nconst basicStore = useBasicStore()\n\nconst loginFunc = () => {\n  loginReq(subForm)\n    .then(({ data }) => {\n      elMessage('登录成功')\n      basicStore.setToken(data?.jwtToken)\n      router.push('/')\n    })\n    .catch((err) => {\n      tipMessage.value = err?.msg\n    })\n    .finally(() => {\n      subLoading.value = false\n    })\n}\n/*\n *  password show or hidden\n * */\nconst passwordType = ref('password')\nconst refPassword:any = ref(null)\nconst showPwd = () => {\n  if (passwordType.value === 'password') {\n    passwordType.value = ''\n  } else {\n    passwordType.value = 'password'\n  }\n  nextTick(() => {\n    refPassword.value.focus()\n  })\n}\n</script>\n\n<style lang=\"scss\" scoped>\n$bg: #2d3a4b;\n$dark_gray: #889aa4;\n$light_gray: #eee;\n.login-container {\n  height: 100vh;\n  width: 100%;\n  background-color: #2d3a4b;\n  .login-form {\n    margin-bottom: 20vh;\n    width: 360px;\n  }\n  .title-container {\n    .title {\n      font-size: 22px;\n      color: #eee;\n      margin: 0 auto 25px auto;\n      text-align: center;\n      font-weight: bold;\n    }\n  }\n}\n\n.svg-container {\n  padding-left: 6px;\n  color: $dark_gray;\n  text-align: center;\n  width: 30px;\n}\n\n//错误提示信息\n.tip-message {\n  color: #e4393c;\n  height: 30px;\n  margin-top: -12px;\n  font-size: 12px;\n}\n//登录按钮\n.login-btn {\n  width: 100%;\n  margin-bottom: 30px;\n}\n.show-pwd {\n  width: 50px;\n  font-size: 16px;\n  color: $dark_gray;\n  cursor: pointer;\n  text-align: center;\n}\n</style>\n\n<style lang=\"scss\">\n//css 样式重置 增加个前缀避免全局污染\n.login-container {\n  .el-input__wrapper {\n    background-color: transparent;\n    box-shadow: none;\n  }\n  .el-form-item {\n    border: 1px solid rgba(255, 255, 255, 0.1);\n    background: rgba(0, 0, 0, 0.1);\n    border-radius: 5px;\n    color: #454545;\n  }\n  .el-input input {\n    background: transparent;\n    border: 0px;\n    -webkit-appearance: none;\n    border-radius: 0px;\n    padding: 10px 5px 10px 15px;\n    color: #fff;\n    height: 42px; //此处调整item的高度\n    caret-color: #fff;\n  }\n  //hiden the input border\n  .el-input__inner {\n    box-shadow: none !important;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/views/nested/menu1/index.vue",
    "content": "<template>\n  <div>\n    <router-view v-slot=\"{ Component }\">\n      <el-alert :closable=\"false\" title=\"menu 1\">\n        <component :is=\"Component\" />\n      </el-alert>\n    </router-view>\n  </div>\n</template>\n"
  },
  {
    "path": "src/views/nested/menu1/menu1-1/index.vue",
    "content": "<template>\n  <div>\n    <router-view v-slot=\"{ Component }\">\n      <div style=\"padding: 15px\">\n        <el-alert :closable=\"false\" title=\"menu 1-1\" type=\"success\">\n          <component :is=\"Component\" />\n        </el-alert>\n      </div>\n    </router-view>\n  </div>\n</template>\n"
  },
  {
    "path": "src/views/nested/menu1/menu1-2/index.vue",
    "content": "<template>\n  <router-view v-slot=\"{ Component }\">\n    <div style=\"padding: 15px\">\n      <el-alert :closable=\"false\" title=\"menu 1-2-2\" type=\"success\">\n        <component :is=\"Component\" />\n      </el-alert>\n    </div>\n  </router-view>\n</template>\n"
  },
  {
    "path": "src/views/nested/menu1/menu1-2/menu1-2-1/index.vue",
    "content": "<template>\n  <div style=\"padding: 30px\">\n    <el-alert :closable=\"false\" title=\"menu 1-2-1\" type=\"warning\" />\n  </div>\n</template>\n"
  },
  {
    "path": "src/views/nested/menu1/menu1-2/menu1-2-2/index.vue",
    "content": "<template>\n  <div style=\"padding: 30px\">\n    <el-alert :closable=\"false\" title=\"menu 1-2-2\" type=\"warning\" />\n  </div>\n</template>\n"
  },
  {
    "path": "src/views/nested/menu1/menu1-3/index.vue",
    "content": "<template>\n  <div>\n    <el-alert :closable=\"false\" title=\"menu 1-3\" type=\"success\" />\n  </div>\n</template>\n"
  },
  {
    "path": "src/views/nested/menu2/index.vue",
    "content": "<template>\n  <div style=\"padding: 15px\">\n    <el-alert :closable=\"false\" title=\"menu 2\" />\n  </div>\n</template>\n<script setup lang=\"ts\"></script>\n"
  },
  {
    "path": "src/views/redirect/index.tsx",
    "content": "import { defineComponent } from 'vue'\nexport default defineComponent({\n  setup() {\n    const route = useRoute()\n    const router = useRouter()\n    onBeforeMount(() => {\n      const { params, query } = route\n      const { path } = params\n      router.replace({ path: `/${path}`, query })\n    })\n    return () => <div> </div>\n  }\n})\n"
  },
  {
    "path": "src/views/setting-switch/SettingSwitch.vue",
    "content": "<template>\n  <div class=\"scroll-y\">\n    <h3 class=\"mb-20px\">props operate demo of settings.js</h3>\n    <div class=\"rowSS\">\n      <div class=\"mb-10px\">\n        <div class=\"font-bold text-20px\">page layout related</div>\n        <div class=\"mt-20px\">\n          sidebarLogo：\n          <el-switch v-model=\"settings.sidebarLogo\" />\n        </div>\n        <div class=\"mt-30px\">\n          showNavbarTitle：\n          <el-switch v-model=\"settings.showNavbarTitle\" />\n        </div>\n        <div class=\"mt-30px\">\n          ShowDropDown：\n          <el-switch v-model=\"settings.ShowDropDown\" />\n        </div>\n        <div class=\"mt-30px\">\n          showHamburger：\n          <el-switch v-model=\"settings.showHamburger\" />\n        </div>\n        <div class=\"mt-30px\">\n          showLeftMenu：\n          <el-switch v-model=\"settings.showLeftMenu\" />\n        </div>\n        <div class=\"mt-30px\">\n          showTagsView：\n          <el-switch v-model=\"settings.showTagsView\" />\n        </div>\n        <div class=\"mt-30px\">\n          showTopNavbar：\n          <el-switch v-model=\"settings.showTopNavbar\" />\n        </div>\n      </div>\n      <div class=\"mb-10px ml-60px\">\n        <div class=\"font-bold text-20px\">page animation related</div>\n        <div class=\"mt-20px\">mainNeedAnimation：places to \"settings file\" for setting</div>\n        <div class=\"mt-30px\">\n          isNeedNprogress：\n          <el-switch v-model=\"settings.isNeedNprogress\" />\n        </div>\n      </div>\n    </div>\n  </div>\n</template>\n\n<script setup>\nconst { settings } = storeToRefs(useBasicStore())\n</script>\n"
  },
  {
    "path": "src/views/setting-switch/index.vue",
    "content": "<template>\n  <div class=\"scroll-y\">\n    <h3 class=\"mb-20px\">props operate demo of settings.js</h3>\n    <div class=\"rowSS\">\n      <div class=\"mb-10px\">\n        <div class=\"font-bold text-20px\">page layout related</div>\n        <div class=\"mt-20px\">\n          sidebarLogo：\n          <el-switch v-model=\"settings.sidebarLogo\" />\n        </div>\n        <div class=\"mt-30px\">\n          showNavbarTitle：\n          <el-switch v-model=\"settings.showNavbarTitle\" />\n        </div>\n        <div class=\"mt-30px\">\n          ShowDropDown：\n          <el-switch v-model=\"settings.ShowDropDown\" />\n        </div>\n        <div class=\"mt-30px\">\n          showHamburger：\n          <el-switch v-model=\"settings.showHamburger\" />\n        </div>\n        <div class=\"mt-30px\">\n          showLeftMenu：\n          <el-switch v-model=\"settings.showLeftMenu\" />\n        </div>\n        <div class=\"mt-30px\">\n          showTagsView：\n          <el-switch v-model=\"settings.showTagsView\" />\n        </div>\n        <div class=\"mt-30px\">\n          showTopNavbar：\n          <el-switch v-model=\"settings.showTopNavbar\" />\n        </div>\n      </div>\n      <div class=\"mb-10px ml-60px\">\n        <div class=\"font-bold text-20px\">page animation related</div>\n        <div class=\"mt-20px\">mainNeedAnimation：places to \"settings file\" for setting</div>\n        <div class=\"mt-30px\">\n          isNeedNprogress：\n          <el-switch v-model=\"settings.isNeedNprogress\" />\n        </div>\n      </div>\n    </div>\n  </div>\n</template>\n\n<script setup>\nconst { settings } = storeToRefs(useBasicStore())\n</script>\n"
  },
  {
    "path": "ts-out-dir/package.json",
    "content": "{\n    \"name\": \"vue3-admin-ts\",\n    \"version\": \"2.0.0-rc2\",\n    \"license\": \"MIT\",\n    \"author\": \"kuanghua\",\n    \"packageManager\": \"pnpm@7.9.0\",\n    \"scripts\": {\n        \"dev\": \"vite --mode serve-dev\",\n        \"test\": \"vite --mode serve-test\",\n        \"build:test\": \"vite build --mode  build-test\",\n        \"build\": \"vite build --mode build\",\n        \"preview:build\": \"npm run build && vite preview \",\n        \"preview\": \"vite preview \",\n        \"lint\": \"eslint --ext .js,.jsx,.vue,.ts,.tsx src --fix\",\n        \"prepare\": \"husky install\",\n        \"test:unit\": \"vue-cli-service test:unit\",\n        \"test:watchAll\": \"vue-cli-service test:unit --watchAll\",\n        \"test:cov\": \"vue-cli-service test:unit --coverage\",\n        \"test:majestic\": \"majestic\",\n        \"vitest\": \"vitest --ui\",\n        \"tsc-check\": \"tsc\",\n        \"coverage\": \"vitest run --coverage\"\n    },\n    \"dependencies\": {\n        \"@element-plus/icons-vue\": \"^2.0.4\",\n        \"axios\": \"0.21.3\",\n        \"echarts\": \"5.3.2\",\n        \"element-plus\": \"^2.2.9\",\n        \"js-error-collection\": \"^1.0.7\",\n        \"mitt\": \"3.0.0\",\n        \"moment-mini\": \"2.22.1\",\n        \"nprogress\": \"0.2.0\",\n        \"path-browserify\": \"^1.0.1\",\n        \"path-to-regexp\": \"^6.2.1\",\n        \"pinia\": \"^2.0.16\",\n        \"pinia-plugin-persistedstate\": \"2.3.0\",\n        \"vue\": \"^3.2.37\",\n        \"vue-clipboard3\": \"^2.0.0\",\n        \"vue-router\": \"^4.1.5\"\n    },\n    \"devDependencies\": {\n        \"@babel/eslint-parser\": \"7.16.3\",\n        \"@types/echarts\": \"4.9.7\",\n        \"@types/mockjs\": \"1.0.6\",\n        \"@types/node\": \"^17.0.35\",\n        \"@types/path-browserify\": \"^1.0.0\",\n        \"@typescript-eslint/eslint-plugin\": \"5.30.0\",\n        \"@typescript-eslint/parser\": \"5.30.0\",\n        \"@vitejs/plugin-legacy\": \"^2.2.0\",\n        \"@vitejs/plugin-vue\": \"^2.3.3\",\n        \"@vitejs/plugin-vue-jsx\": \"^2.0.1\",\n        \"@vitest/coverage-c8\": \"^0.22.1\",\n        \"@vitest/ui\": \"^0.22.1\",\n        \"@vue/cli-plugin-unit-jest\": \"4.5.17\",\n        \"@vue/cli-service\": \"4.5.17\",\n        \"@vue/test-utils\": \"^2.0.2\",\n        \"@vueuse/core\": \"^8.7.5\",\n        \"eslint\": \"8.18.0\",\n        \"eslint-config-prettier\": \"8.5.0\",\n        \"eslint-define-config\": \"1.5.1\",\n        \"eslint-plugin-eslint-comments\": \"3.2.0\",\n        \"eslint-plugin-import\": \"2.26.0\",\n        \"eslint-plugin-jsonc\": \"^2.3.0\",\n        \"eslint-plugin-markdown\": \"^3.0.0\",\n        \"eslint-plugin-prettier\": \"4.1.0\",\n        \"eslint-plugin-unicorn\": \"^43.0.2\",\n        \"eslint-plugin-vue\": \"9.1.1\",\n        \"husky\": \"7.0.2\",\n        \"jsdom\": \"16.4.0\",\n        \"jsonc-eslint-parser\": \"^2.1.0\",\n        \"majestic\": \"1.8.1\",\n        \"mockjs\": \"1.1.0\",\n        \"prettier\": \"2.2.1\",\n        \"resize-observer-polyfill\": \"^1.5.1\",\n        \"rollup-plugin-visualizer\": \"^5.8.3\",\n        \"sass\": \"^1.52.1\",\n        \"svg-sprite-loader\": \"6.0.11\",\n        \"typescript\": \"^4.7.2\",\n        \"unocss\": \"^0.33.5\",\n        \"unplugin-auto-import\": \"^0.11.2\",\n        \"unplugin-vue-components\": \"^0.22.8\",\n        \"unplugin-vue-define-options\": \"^0.12.2\",\n        \"vite\": \"^3.1.8\",\n        \"vite-plugin-html\": \"^3.2.0\",\n        \"vite-plugin-mkcert\": \"^1.7.2\",\n        \"vite-plugin-mock\": \"^2.9.6\",\n        \"vite-plugin-svg-icons\": \"^2.0.1\",\n        \"vitest\": \"^0.22.1\",\n        \"vue-tsc\": \"^0.34.16\"\n    },\n    \"pnpm\": {\n        \"peerDependencyRules\": {\n            \"ignoreMissing\": [\n                \"html-webpack-plugin\",\n                \"vite-plugin-mock\",\n                \"unplugin-auto-import\",\n                \"unplugin-vue-components\",\n                \"vue-template-compiler\",\n                \"unocss\",\n                \"unplugin\",\n                \"vite-plugin-mock\",\n                \"@vitejs/plugin-legacy\",\n                \"@vitejs/plugin-vue\",\n                \"@vitejs/*\",\n                \"@babel/*\",\n                \"vite\",\n                \"vue\",\n                \"@unocss/vite\",\n                \"rollup\",\n                \"vue-jest\",\n                \"@babel/*\"\n            ]\n        }\n    },\n    \"browserslist\": [\n        \"> 1%\",\n        \"not ie 11\",\n        \"not op_mini all\"\n    ],\n    \"engines\": {\n        \"node\": \">= 16 <18\",\n        \"pnpm\": \">= 6 <8\"\n    }\n}\n"
  },
  {
    "path": "ts-out-dir/src/api/user.d.ts",
    "content": "export declare const userInfoReq: () => Promise<any>;\nexport declare const loginReq: (subForm: any) => import(\"axios\").AxiosPromise<any>;\nexport declare const loginOutReq: () => import(\"axios\").AxiosPromise<any>;\n"
  },
  {
    "path": "ts-out-dir/src/api/user.js",
    "content": "import axiosReq from '@/utils/axios-req';\nexport const userInfoReq = () => {\n    return new Promise((resolve) => {\n        const reqConfig = {\n            url: '/basis-func/user/getUserInfo',\n            params: { plateFormId: 2 },\n            method: 'post'\n        };\n        axiosReq(reqConfig).then(({ data }) => {\n            resolve(data);\n        });\n    });\n};\nexport const loginReq = (subForm) => {\n    return axiosReq({\n        url: '/basis-func/user/loginValid',\n        params: subForm,\n        method: 'post'\n    });\n};\nexport const loginOutReq = () => {\n    return axiosReq({\n        url: '/basis-func/user/loginValid',\n        method: 'post'\n    });\n};\n"
  },
  {
    "path": "ts-out-dir/src/directives/button-codes.d.ts",
    "content": "declare const _default: {\n    mounted(el: any, binding: any): void;\n    componentUpdated(el: any, binding: any): void;\n};\nexport default _default;\n"
  },
  {
    "path": "ts-out-dir/src/directives/button-codes.js",
    "content": "import { useBasicStore } from '@/store/basic';\nfunction checkPermission(el, { value }) {\n    if (value && Array.isArray(value)) {\n        if (value.length) {\n            const permissionRoles = value;\n            const hasPermission = useBasicStore().buttonCodes?.some((code) => permissionRoles.includes(code));\n            if (!hasPermission)\n                el.parentNode && el.parentNode.removeChild(el);\n        }\n    }\n    else {\n        throw new Error(`need roles! Like v-permission=\"['admin','editor']\"`);\n    }\n}\nexport default {\n    mounted(el, binding) {\n        checkPermission(el, binding);\n    },\n    componentUpdated(el, binding) {\n        checkPermission(el, binding);\n    }\n};\n"
  },
  {
    "path": "ts-out-dir/src/directives/codes-permission.d.ts",
    "content": "declare const _default: {\n    mounted(el: any, binding: any): void;\n    componentUpdated(el: any, binding: any): void;\n};\nexport default _default;\n"
  },
  {
    "path": "ts-out-dir/src/directives/codes-permission.js",
    "content": "import { useBasicStore } from '@/store/basic';\nfunction checkPermission(el, { value }) {\n    if (value && Array.isArray(value)) {\n        if (value.length > 0) {\n            const permissionRoles = value;\n            const hasPermission = useBasicStore().codes?.some((role) => permissionRoles.includes(role));\n            if (!hasPermission)\n                el.parentNode && el.parentNode.removeChild(el);\n        }\n    }\n    else {\n        throw new Error(`need codes! Like v-codes-permission=\"['admin','editor']\"`);\n    }\n}\nexport default {\n    mounted(el, binding) {\n        checkPermission(el, binding);\n    },\n    componentUpdated(el, binding) {\n        checkPermission(el, binding);\n    }\n};\n"
  },
  {
    "path": "ts-out-dir/src/directives/index.d.ts",
    "content": "export default function (app: any): void;\n"
  },
  {
    "path": "ts-out-dir/src/directives/index.js",
    "content": "import buttonCodes from './button-codes';\nimport codesPermission from './codes-permission';\nimport rolesPermission from './roles-permission';\nexport default function (app) {\n    app.directive('ButtonCodes', buttonCodes);\n    app.directive('CodesPermission', codesPermission);\n    app.directive('RolesPermission', rolesPermission);\n}\n"
  },
  {
    "path": "ts-out-dir/src/directives/roles-permission.d.ts",
    "content": "declare const _default: {\n    mounted(el: any, binding: any): void;\n    componentUpdated(el: any, binding: any): void;\n};\nexport default _default;\n"
  },
  {
    "path": "ts-out-dir/src/directives/roles-permission.js",
    "content": "import { useBasicStore } from '@/store/basic';\nfunction checkPermission(el, { value }) {\n    if (value && Array.isArray(value)) {\n        if (value.length > 0) {\n            const permissionRoles = value;\n            const hasPermission = useBasicStore().roles?.some((role) => permissionRoles.includes(role));\n            if (!hasPermission)\n                el.parentNode && el.parentNode.removeChild(el);\n        }\n    }\n    else {\n        throw new Error(`need roles! Like v-roles-permission=\"['admin','editor']\"`);\n    }\n}\nexport default {\n    mounted(el, binding) {\n        checkPermission(el, binding);\n    },\n    componentUpdated(el, binding) {\n        checkPermission(el, binding);\n    }\n};\n"
  },
  {
    "path": "ts-out-dir/src/hooks/use-common.d.ts",
    "content": "export declare const sleepTimeout: (time: number) => Promise<unknown>;\nexport declare const useCommon: () => {\n    totalPage: import(\"vue\").Ref<number>;\n    startEndArr: import(\"vue\").Ref<never[]>;\n    searchForm: import(\"vue\").Ref<{}>;\n    dialogTitle: import(\"vue\").Ref<string>;\n    detailDialog: import(\"vue\").Ref<boolean>;\n};\nexport declare function cloneDeep(value: any): any;\nexport declare const copyValueToClipboard: (value: any) => void;\n"
  },
  {
    "path": "ts-out-dir/src/hooks/use-common.js",
    "content": "import { reactive, toRefs } from 'vue';\nimport useClipboard from 'vue-clipboard3';\nimport { ElMessage } from 'element-plus';\nexport const sleepTimeout = (time) => {\n    return new Promise((resolve) => {\n        const timer = setTimeout(() => {\n            clearTimeout(timer);\n            resolve(null);\n        }, time);\n    });\n};\nexport const useCommon = () => {\n    const state = reactive({\n        totalPage: 0,\n        startEndArr: [],\n        searchForm: {},\n        dialogTitle: '',\n        detailDialog: false\n    });\n    return {\n        ...toRefs(state)\n    };\n};\nexport function cloneDeep(value) {\n    return JSON.parse(JSON.stringify(value));\n}\nconst { toClipboard } = useClipboard();\nexport const copyValueToClipboard = (value) => {\n    toClipboard(JSON.stringify(value));\n    ElMessage.success('复制成功');\n};\n"
  },
  {
    "path": "ts-out-dir/src/hooks/use-element.d.ts",
    "content": "import type { EpPropMergeType } from 'element-plus/es/utils';\nexport declare const useElement: () => {\n    tableData: import(\"vue\").Ref<never[]>;\n    rowDeleteIdArr: import(\"vue\").Ref<never[]>;\n    loadingId: import(\"vue\").Ref<null>;\n    formModel: import(\"vue\").Ref<{}>;\n    subForm: import(\"vue\").Ref<{}>;\n    searchForm: import(\"vue\").Ref<{}>;\n    formRules: import(\"vue\").Ref<{\n        isNull: (msg: string) => {\n            required: boolean;\n            message: string;\n            trigger: string;\n        }[];\n        isNotNull: (msg: string) => {\n            required: boolean;\n            message: string;\n            trigger: string;\n        }[];\n        upZeroInt: (msg: string) => {\n            required: boolean;\n            validator: (rule: any, value: any, callback: any) => void;\n            trigger: string;\n        }[];\n        zeroInt: (msg: string) => {\n            required: boolean;\n            validator: (rule: any, value: any, callback: any) => void;\n            trigger: string;\n        }[];\n        money: (msg: string) => {\n            required: boolean;\n            validator: (rule: any, value: any, callback: any) => void;\n            trigger: string;\n        }[];\n        phone: (msg: string) => {\n            required: boolean;\n            validator: (rule: any, value: any, callback: any) => void;\n            trigger: string;\n        }[];\n        email: (msg: string) => {\n            required: boolean;\n            validator: (rule: any, value: any, callback: any) => void;\n            trigger: string;\n        }[];\n    }>;\n    datePickerOptions: import(\"vue\").Ref<{\n        disabledDate: (time: any) => boolean;\n    }>;\n    startEndArr: import(\"vue\").Ref<never[]>;\n    dialogTitle: import(\"vue\").Ref<string>;\n    detailDialog: import(\"vue\").Ref<boolean>;\n    isDialogEdit: import(\"vue\").Ref<boolean>;\n    dialogVisible: import(\"vue\").Ref<boolean>;\n    tableLoading: import(\"vue\").Ref<boolean>;\n    treeData: import(\"vue\").Ref<never[]>;\n    defaultProps: import(\"vue\").Ref<{\n        children: string;\n        label: string;\n    }>;\n};\nexport declare const elMessage: (message: string, type?: any) => void;\nexport declare const elLoading: () => void;\nexport declare const closeLoading: () => void;\nexport declare const elNotify: (message: string, type: EpPropMergeType<any, any, any> | undefined, title: string, duration: number) => void;\nexport declare const elConfirmNoCancelBtn: (title: string, message: string) => Promise<import(\"element-plus\").MessageBoxData>;\nexport declare const elConfirm: (title: string, message: string) => Promise<import(\"element-plus\").MessageBoxData>;\nexport declare const casHandleChange: () => void;\n"
  },
  {
    "path": "ts-out-dir/src/hooks/use-element.js",
    "content": "import { reactive, ref, toRefs } from 'vue';\nimport { ElLoading, ElMessage, ElMessageBox, ElNotification } from 'element-plus';\nexport const useElement = () => {\n    const upZeroInt = (rule, value, callback, msg) => {\n        if (!value) {\n            callback(new Error(`${msg}不能为空`));\n        }\n        if (/^\\+?[1-9]\\d*$/.test(value)) {\n            callback();\n        }\n        else {\n            callback(new Error(`${msg}输入有误`));\n        }\n    };\n    const zeroInt = (rule, value, callback, msg) => {\n        if (!value) {\n            callback(new Error(`${msg}不能为空`));\n        }\n        if (/^\\+?[0-9]\\d*$/.test(value)) {\n            callback();\n        }\n        else {\n            callback(new Error(`${msg}输入有误`));\n        }\n    };\n    const money = (rule, value, callback, msg) => {\n        if (!value) {\n            callback(new Error(`${msg}不能为空`));\n        }\n        if (/((^[1-9]\\d*)|^0)(\\.\\d{0,2}){0,1}$/.test(value)) {\n            callback();\n        }\n        else {\n            callback(new Error(`${msg}输入有误`));\n        }\n    };\n    const phone = (rule, value, callback, msg) => {\n        if (!value) {\n            callback(new Error(`${msg}不能为空`));\n        }\n        if (/^0?1[0-9]{10}$/.test(value)) {\n            callback();\n        }\n        else {\n            callback(new Error(`${msg}输入有误`));\n        }\n    };\n    const email = (rule, value, callback, msg) => {\n        if (!value) {\n            callback(new Error(`${msg}不能为空`));\n        }\n        if (/(^([a-zA-Z]|[0-9])(\\w|-)+@[a-zA-Z0-9]+\\.([a-zA-Z]{2,4}))$/.test(value)) {\n            callback();\n        }\n        else {\n            callback(new Error(`${msg}`));\n        }\n    };\n    const state = reactive({\n        tableData: [],\n        rowDeleteIdArr: [],\n        loadingId: null,\n        formModel: {},\n        subForm: {},\n        searchForm: {},\n        formRules: {\n            isNull: (msg) => [{ required: false, message: `${msg}`, trigger: 'blur' }],\n            isNotNull: (msg) => [{ required: true, message: `${msg}`, trigger: 'blur' }],\n            upZeroInt: (msg) => [\n                { required: true, validator: (rule, value, callback) => upZeroInt(rule, value, callback, msg), trigger: 'blur' }\n            ],\n            zeroInt: (msg) => [\n                { required: true, validator: (rule, value, callback) => zeroInt(rule, value, callback, msg), trigger: 'blur' }\n            ],\n            money: (msg) => [\n                { required: true, validator: (rule, value, callback) => money(rule, value, callback, msg), trigger: 'blur' }\n            ],\n            phone: (msg) => [\n                { required: true, validator: (rule, value, callback) => phone(rule, value, callback, msg), trigger: 'blur' }\n            ],\n            email: (msg) => [\n                { required: true, validator: (rule, value, callback) => email(rule, value, callback, msg), trigger: 'blur' }\n            ]\n        },\n        datePickerOptions: {\n            disabledDate: (time) => {\n                return time.getTime() < Date.now() - 86400000;\n            }\n        },\n        startEndArr: [],\n        dialogTitle: '添加',\n        detailDialog: false,\n        isDialogEdit: false,\n        dialogVisible: false,\n        tableLoading: false,\n        treeData: [],\n        defaultProps: {\n            children: 'children',\n            label: 'label'\n        }\n    });\n    return {\n        ...toRefs(state)\n    };\n};\nexport const elMessage = (message, type) => {\n    ElMessage({\n        showClose: true,\n        message: message || '成功',\n        type: type || 'success',\n        center: false\n    });\n};\nlet loadingId = null;\nexport const elLoading = () => {\n    loadingId = ElLoading.service({\n        lock: true,\n        text: '数据载入中',\n        spinner: 'el-icon-loading',\n        background: 'rgba(0, 0, 0, 0.1)'\n    });\n};\nexport const closeLoading = () => {\n    loadingId.close();\n};\nexport const elNotify = (message, type, title, duration) => {\n    ElNotification({\n        title: title || '提示',\n        type: type || 'success',\n        message: message || '请传入提示消息',\n        position: 'top-right',\n        duration: duration || 2500,\n        offset: 40\n    });\n};\nexport const elConfirmNoCancelBtn = (title, message) => {\n    return ElMessageBox({\n        message: message || '你确定要删除吗',\n        title: title || '确认框',\n        confirmButtonText: '确定',\n        cancelButtonText: '取消',\n        showCancelButton: false,\n        type: 'warning'\n    });\n};\nexport const elConfirm = (title, message) => {\n    return ElMessageBox({\n        message: message || '你确定要删除吗',\n        title: title || '确认框',\n        confirmButtonText: '确定',\n        cancelButtonText: '取消',\n        type: 'warning'\n    });\n};\nconst cascaderKey = ref();\nexport const casHandleChange = () => {\n    cascaderKey.value += cascaderKey.value;\n};\n"
  },
  {
    "path": "ts-out-dir/src/hooks/use-error-log.d.ts",
    "content": "export declare const useErrorLog: () => void;\n"
  },
  {
    "path": "ts-out-dir/src/hooks/use-error-log.js",
    "content": "import { jsErrorCollection } from 'js-error-collection';\nimport pack from '../../package.json';\nimport settings from '@/settings';\nimport bus from '@/utils/bus';\nimport axiosReq from '@/utils/axios-req';\nconst reqUrl = '/integration-front/errorCollection/insert';\nconst errorLogReq = (errLog) => {\n    axiosReq({\n        url: reqUrl,\n        data: {\n            pageUrl: window.location.href,\n            errorLog: errLog,\n            browserType: navigator.userAgent,\n            version: pack.version\n        },\n        method: 'post'\n    }).then(() => {\n        bus.emit('reloadErrorPage', {});\n    });\n};\nexport const useErrorLog = () => {\n    if (settings.errorLog?.includes(import.meta.env.VITE_APP_ENV)) {\n        jsErrorCollection({ runtimeError: true, rejectError: true, consoleError: true }, (errLog) => {\n            if (!errLog.includes(reqUrl))\n                errorLogReq(errLog);\n        });\n    }\n};\n"
  },
  {
    "path": "ts-out-dir/src/hooks/use-layout.d.ts",
    "content": "export declare function isExternal(path: any): boolean;\nexport declare function resizeHandler(): void;\n"
  },
  {
    "path": "ts-out-dir/src/hooks/use-layout.js",
    "content": "import { onBeforeMount, onBeforeUnmount, onMounted } from 'vue';\nimport { useBasicStore } from '@/store/basic';\nexport function isExternal(path) {\n    return /^(https?:|mailto:|tel:)/.test(path);\n}\nexport function resizeHandler() {\n    const { body } = document;\n    const WIDTH = 992;\n    const basicStore = useBasicStore();\n    const isMobile = () => {\n        const rect = body.getBoundingClientRect();\n        return rect.width - 1 < WIDTH;\n    };\n    const resizeHandler = () => {\n        if (!document.hidden) {\n            if (isMobile()) {\n                basicStore.setSidebarOpen(false);\n            }\n            else {\n                basicStore.setSidebarOpen(true);\n            }\n        }\n    };\n    onBeforeMount(() => {\n        window.addEventListener('resize', resizeHandler);\n    });\n    onMounted(() => {\n        if (isMobile()) {\n            basicStore.setSidebarOpen(false);\n        }\n        else {\n            basicStore.setSidebarOpen(true);\n        }\n    });\n    onBeforeUnmount(() => {\n        window.removeEventListener('resize', resizeHandler);\n    });\n}\n"
  },
  {
    "path": "ts-out-dir/src/hooks/use-permission.d.ts",
    "content": "import type { RouterTypes } from '~/basic';\nimport 'nprogress/nprogress.css';\nexport declare const filterAsyncRoutesByMenuList: (menuList: any) => RouterTypes;\nexport declare function filterAsyncRoutesByRoles(routes: any, roles: any): RouterTypes;\nexport declare function filterAsyncRouterByCodes(codesRoutes: any, codes: any): RouterTypes;\nexport declare function filterAsyncRouter({ menuList, roles, codes }: {\n    menuList: any;\n    roles: any;\n    codes: any;\n}): void;\nexport declare function resetRouter(): void;\nexport declare function resetState(): void;\nexport declare function freshRouter(data: any): void;\nexport declare const progressStart: () => void;\nexport declare const progressClose: () => void;\n"
  },
  {
    "path": "ts-out-dir/src/hooks/use-permission.js",
    "content": "import NProgress from 'nprogress';\nimport Layout from '@/layout/index.vue';\nimport router, { asyncRoutes, constantRoutes, roleCodeRoutes } from '@/router';\nimport 'nprogress/nprogress.css';\nimport { useBasicStore } from '@/store/basic';\nconst buttonCodes = [];\nexport const filterAsyncRoutesByMenuList = (menuList) => {\n    const filterRouter = [];\n    menuList.forEach((route) => {\n        if (route.category === 3) {\n            buttonCodes.push(route.code);\n        }\n        else {\n            const itemFromReqRouter = getRouteItemFromReqRouter(route);\n            if (route.children?.length) {\n                itemFromReqRouter.children = filterAsyncRoutesByMenuList(route.children);\n            }\n            filterRouter.push(itemFromReqRouter);\n        }\n    });\n    return filterRouter;\n};\nconst getRouteItemFromReqRouter = (route) => {\n    const tmp = { meta: { title: '' } };\n    const routeKeyArr = ['path', 'component', 'redirect', 'alwaysShow', 'name', 'hidden'];\n    const metaKeyArr = ['title', 'activeMenu', 'elSvgIcon', 'icon'];\n    const modules = import.meta.glob('../views/**/**.vue');\n    routeKeyArr.forEach((fItem) => {\n        if (fItem === 'component') {\n            if (route[fItem] === 'Layout') {\n                tmp[fItem] = Layout;\n            }\n            else {\n                tmp[fItem] = modules[`../views/${route[fItem]}`];\n            }\n        }\n        else if (fItem === 'path' && route.parentId === 0) {\n            tmp[fItem] = `/${route[fItem]}`;\n        }\n        else if (['hidden', 'alwaysShow'].includes(fItem)) {\n            tmp[fItem] = !!route[fItem];\n        }\n        else if (['name'].includes(fItem)) {\n            tmp[fItem] = route['code'];\n        }\n        else if (route[fItem]) {\n            tmp[fItem] = route[fItem];\n        }\n    });\n    metaKeyArr.forEach((fItem) => {\n        if (route[fItem] && tmp.meta)\n            tmp.meta[fItem] = route[fItem];\n    });\n    if (route.extra) {\n        Object.entries(route.extra.parse(route.extra)).forEach(([key, value]) => {\n            if (key === 'meta' && tmp.meta) {\n                tmp.meta[key] = value;\n            }\n            else {\n                tmp[key] = value;\n            }\n        });\n    }\n    return tmp;\n};\nexport function filterAsyncRoutesByRoles(routes, roles) {\n    const res = [];\n    routes.forEach((route) => {\n        const tmp = { ...route };\n        if (hasPermission(roles, tmp)) {\n            if (tmp.children) {\n                tmp.children = filterAsyncRoutesByRoles(tmp.children, roles);\n            }\n            res.push(tmp);\n        }\n    });\n    return res;\n}\nfunction hasPermission(roles, route) {\n    if (route?.meta?.roles) {\n        return roles?.some((role) => route.meta.roles.includes(role));\n    }\n    else {\n        return true;\n    }\n}\nexport function filterAsyncRouterByCodes(codesRoutes, codes) {\n    const filterRouter = [];\n    codesRoutes.forEach((routeItem) => {\n        if (hasCodePermission(codes, routeItem)) {\n            if (routeItem.children)\n                routeItem.children = filterAsyncRouterByCodes(routeItem.children, codes);\n            filterRouter.push(routeItem);\n        }\n    });\n    return filterRouter;\n}\nfunction hasCodePermission(codes, routeItem) {\n    if (routeItem.meta?.code) {\n        return codes.includes(routeItem.meta.code) || routeItem.hidden;\n    }\n    else {\n        return true;\n    }\n}\nexport function filterAsyncRouter({ menuList, roles, codes }) {\n    const basicStore = useBasicStore();\n    let accessRoutes = [];\n    const permissionMode = basicStore.settings?.permissionMode;\n    if (permissionMode === 'rbac') {\n        accessRoutes = filterAsyncRoutesByMenuList(menuList);\n    }\n    else if (permissionMode === 'roles') {\n        accessRoutes = filterAsyncRoutesByRoles(roleCodeRoutes, roles);\n    }\n    else {\n        accessRoutes = filterAsyncRouterByCodes(roleCodeRoutes, codes);\n    }\n    accessRoutes.forEach((route) => router.addRoute(route));\n    asyncRoutes.forEach((item) => router.addRoute(item));\n    basicStore.setFilterAsyncRoutes(accessRoutes);\n}\nexport function resetRouter() {\n    const routeNameSet = new Set();\n    router.getRoutes().forEach((fItem) => {\n        if (fItem.name)\n            routeNameSet.add(fItem.name);\n    });\n    routeNameSet.forEach((setItem) => router.removeRoute(setItem));\n    constantRoutes.forEach((feItem) => router.addRoute(feItem));\n}\nexport function resetState() {\n    resetRouter();\n    useBasicStore().resetState();\n}\nexport function freshRouter(data) {\n    resetRouter();\n    filterAsyncRouter(data);\n}\nNProgress.configure({ showSpinner: false });\nexport const progressStart = () => {\n    NProgress.start();\n};\nexport const progressClose = () => {\n    NProgress.done();\n};\n"
  },
  {
    "path": "ts-out-dir/src/hooks/use-self-router.d.ts",
    "content": "export declare const getQueryParam: () => any;\nexport declare const routerPush: (name: any, params: any) => void;\nexport declare const routerReplace: (name: any, params: any) => void;\nexport declare const routerBack: () => void;\n"
  },
  {
    "path": "ts-out-dir/src/hooks/use-self-router.js",
    "content": "import router from '@/router';\nexport const getQueryParam = () => {\n    const route = router.currentRoute;\n    if (route.value?.query.params) {\n        return JSON.parse(route.value.query.params);\n    }\n};\nexport const routerPush = (name, params) => {\n    let data = {};\n    if (params) {\n        data = {\n            params: JSON.stringify(params)\n        };\n    }\n    else {\n        data = {};\n    }\n    router.push({\n        name,\n        query: data\n    });\n};\nexport const routerReplace = (name, params) => {\n    let data = {};\n    if (params) {\n        data = {\n            params: JSON.stringify(params)\n        };\n    }\n    else {\n        data = {};\n    }\n    router.replace({\n        name,\n        query: data\n    });\n};\nexport const routerBack = () => {\n    router.go(-1);\n};\n"
  },
  {
    "path": "ts-out-dir/src/hooks/use-table.d.ts",
    "content": "export declare const useTable: (searchForm: any, selectPageReq: any) => {\n    pageNum: import(\"vue\").Ref<number>;\n    pageSize: import(\"vue\").Ref<number>;\n    totalPage: import(\"vue\").Ref<number>;\n    tableListData: import(\"vue\").Ref<never[]>;\n    tableListReq: (config: any) => import(\"axios\").AxiosPromise<any>;\n    dateRangePacking: (timeArr: any) => void;\n    multipleSelection: import(\"vue\").Ref<ObjKeys[]>;\n    handleSelectionChange: (val: any) => void;\n    handleCurrentChange: (val: any) => void;\n    handleSizeChange: (val: any) => void;\n    resetPageReq: () => void;\n    multiDelBtnDill: (reqConfig: any) => void;\n    tableDelDill: (row: any, reqConfig: any) => void;\n};\n"
  },
  {
    "path": "ts-out-dir/src/hooks/use-table.js",
    "content": "import { ref } from 'vue';\nimport momentMini from 'moment-mini';\nimport { elConfirm, elMessage } from './use-element';\nexport const useTable = (searchForm, selectPageReq) => {\n    const tableListData = ref([]);\n    const totalPage = ref(0);\n    const pageNum = ref(1);\n    const pageSize = ref(20);\n    const tableListReq = (config) => {\n        const data = Object.assign({\n            pageNum: pageNum.value,\n            pageSize: pageSize.value\n        }, JSON.parse(JSON.stringify(searchForm)));\n        Object.keys(data).forEach((fItem) => {\n            if (['', null, undefined, Number.NaN].includes(data[fItem]))\n                delete data[fItem];\n            if (config.method === 'get') {\n                if (Array.isArray(data[fItem]))\n                    delete data[fItem];\n                if (data[fItem] instanceof Object)\n                    delete data[fItem];\n            }\n        });\n        const reqConfig = {\n            data,\n            ...config\n        };\n        return axiosReq(reqConfig);\n    };\n    const dateRangePacking = (timeArr) => {\n        if (timeArr && timeArr.length === 2) {\n            searchForm.startTime = timeArr[0];\n            if (searchForm.endTime) {\n                searchForm.endTime = momentMini(timeArr[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss');\n            }\n        }\n        else {\n            searchForm.startTime = '';\n            searchForm.endTime = '';\n        }\n    };\n    const handleCurrentChange = (val) => {\n        pageNum.value = val;\n        selectPageReq();\n    };\n    const handleSizeChange = (val) => {\n        pageSize.value = val;\n        selectPageReq();\n    };\n    const resetPageReq = () => {\n        pageNum.value = 1;\n        selectPageReq();\n    };\n    const multipleSelection = ref([]);\n    const handleSelectionChange = (val) => {\n        multipleSelection.value = val;\n    };\n    const multiDelBtnDill = (reqConfig) => {\n        let rowDeleteIdArr = [];\n        let deleteNameTitle = '';\n        rowDeleteIdArr = multipleSelection.value.map((mItem) => {\n            deleteNameTitle = `${deleteNameTitle + mItem.id},`;\n            return mItem.id;\n        });\n        if (rowDeleteIdArr.length === 0) {\n            elMessage('表格选项不能为空', 'warning');\n            return;\n        }\n        const stringLength = deleteNameTitle.length - 1;\n        elConfirm('删除', `您确定要删除【${deleteNameTitle.slice(0, stringLength)}】吗`).then(() => {\n            const data = rowDeleteIdArr;\n            axiosReq({\n                data,\n                method: 'DELETE',\n                bfLoading: true,\n                ...reqConfig\n            }).then(() => {\n                elMessage('删除成功');\n                resetPageReq();\n            });\n        });\n    };\n    const tableDelDill = (row, reqConfig) => {\n        elConfirm('确定', `您确定要删除【${row.id}】吗？`).then(() => {\n            axiosReq(reqConfig).then(() => {\n                resetPageReq();\n                elMessage(`【${row.id}】删除成功`);\n            });\n        });\n    };\n    return {\n        pageNum,\n        pageSize,\n        totalPage,\n        tableListData,\n        tableListReq,\n        dateRangePacking,\n        multipleSelection,\n        handleSelectionChange,\n        handleCurrentChange,\n        handleSizeChange,\n        resetPageReq,\n        multiDelBtnDill,\n        tableDelDill\n    };\n};\n"
  },
  {
    "path": "ts-out-dir/src/lib/element-plus.d.ts",
    "content": "export default function (app: any): void;\n"
  },
  {
    "path": "ts-out-dir/src/lib/element-plus.js",
    "content": "import * as AllComponent from 'element-plus';\nconst elementPlusComponentNameArr = ['ElButton'];\nexport default function (app) {\n    elementPlusComponentNameArr.forEach((component) => {\n        app.component(component, AllComponent[component]);\n    });\n}\n"
  },
  {
    "path": "ts-out-dir/src/main.d.ts",
    "content": "import '@/styles/index.scss';\nimport 'virtual:svg-icons-register';\nimport './permission';\nimport './theme/index.scss';\nimport 'uno.css';\nimport 'element-plus/dist/index.css';\n"
  },
  {
    "path": "ts-out-dir/src/main.js",
    "content": "import { createApp } from 'vue';\nimport App from './App.vue';\nconst app = createApp(App);\nimport router from './router';\nimport '@/styles/index.scss';\nimport 'virtual:svg-icons-register';\nimport svgIcon from '@/icons/SvgIcon.vue';\nimport directive from '@/directives';\nimport './permission';\nimport './theme/index.scss';\nimport 'uno.css';\nimport ElementPlus from 'element-plus';\nimport 'element-plus/dist/index.css';\napp.use(ElementPlus);\napp.component('SvgIcon', svgIcon);\ndirective(app);\nimport { createPinia } from 'pinia';\nimport piniaPluginPersistedstate from 'pinia-plugin-persistedstate';\nconst pinia = createPinia();\npinia.use(piniaPluginPersistedstate);\napp.use(pinia);\napp.use(router).mount('#app');\n"
  },
  {
    "path": "ts-out-dir/src/permission.d.ts",
    "content": "export {};\n"
  },
  {
    "path": "ts-out-dir/src/permission.js",
    "content": "import router from '@/router';\nimport { filterAsyncRouter, progressClose, progressStart } from '@/hooks/use-permission';\nimport { useBasicStore } from '@/store/basic';\nimport { userInfoReq } from '@/api/system.ts';\nconst whiteList = ['/login', '/404', '/401'];\nrouter.beforeEach(async (to) => {\n    progressStart();\n    const basicStore = useBasicStore();\n    if (basicStore.token) {\n        if (to.path === '/login') {\n            return '/';\n        }\n        else {\n            if (!basicStore.getUserInfo) {\n                try {\n                    const userData = await userInfoReq();\n                    filterAsyncRouter(userData);\n                    basicStore.setUserInfo(userData);\n                    return { ...to, replace: true };\n                }\n                catch (e) {\n                    console.error(`route permission error${e}`);\n                    basicStore.resetState();\n                    progressClose();\n                    return `/login?redirect=${to.path}`;\n                }\n            }\n            else {\n                return true;\n            }\n        }\n    }\n    else {\n        if (!whiteList.includes(to.path)) {\n            return `/login?redirect=${to.path}`;\n        }\n        else {\n            return true;\n        }\n    }\n});\nrouter.afterEach(() => {\n    progressClose();\n});\n"
  },
  {
    "path": "ts-out-dir/src/router/index.d.ts",
    "content": "import type { RouterTypes } from '~/basic';\nexport declare const constantRoutes: RouterTypes;\nexport declare const roleCodeRoutes: RouterTypes;\nexport declare const asyncRoutes: RouterTypes;\ndeclare const router: import(\"vue-router\").Router;\nexport default router;\n"
  },
  {
    "path": "ts-out-dir/src/router/index.js",
    "content": "import { createRouter, createWebHashHistory } from 'vue-router';\nimport Layout from '@/layout/index.vue';\nexport const constantRoutes = [\n    {\n        path: '/redirect',\n        component: Layout,\n        hidden: true,\n        children: [\n            {\n                path: '/redirect/:path(.*)',\n                component: () => import('@/views/redirect')\n            }\n        ]\n    },\n    {\n        path: '/login',\n        component: () => import('@/views/login/index.vue'),\n        hidden: true\n    },\n    {\n        path: '/404',\n        component: () => import('@/views/error-page/404.vue'),\n        hidden: true\n    },\n    {\n        path: '/401',\n        component: () => import('@/views/error-page/401.vue'),\n        hidden: true\n    },\n    {\n        path: '/',\n        component: Layout,\n        redirect: '/dashboard',\n        children: [\n            {\n                path: 'dashboard',\n                name: 'Dashboard',\n                component: () => import('@/views/dashboard/index.vue'),\n                meta: { title: 'Dashboard', elSvgIcon: 'Fold' }\n            }\n        ]\n    },\n    {\n        path: '/setting-switch',\n        component: Layout,\n        children: [\n            {\n                path: 'index',\n                component: () => import('@/views/setting-switch/index.vue'),\n                name: 'SettingSwitch',\n                meta: { title: 'Setting Switch', icon: 'example', affix: true }\n            }\n        ]\n    },\n    {\n        path: '/error-collection',\n        component: Layout,\n        meta: { title: 'Error Collection', icon: 'eye' },\n        alwaysShow: true,\n        children: [\n            {\n                path: 'error-collection-table-query',\n                component: () => import('@/views/error-collection/ErrorCollectionTableQuery.vue'),\n                name: 'ErrorCollectionTableQuery',\n                meta: { title: 'Index' }\n            },\n            {\n                path: 'error-log-test',\n                component: () => import('@/views/error-log/ErrorLogTest.vue'),\n                name: 'ErrorLogTest',\n                meta: { title: 'ErrorLog Test' }\n            }\n        ]\n    },\n    {\n        path: '/nested',\n        component: Layout,\n        redirect: '/nested/menu1',\n        name: 'Nested',\n        meta: {\n            title: 'Nested',\n            icon: 'nested'\n        },\n        children: [\n            {\n                path: 'menu1',\n                component: () => import('@/views/nested/menu1/index.vue'),\n                name: 'Menu1',\n                meta: { title: 'Menu1' },\n                children: [\n                    {\n                        path: 'menu1-1',\n                        component: () => import('@/views/nested/menu1/menu1-1/index.vue'),\n                        name: 'Menu1-1',\n                        meta: { title: 'Menu1-1' }\n                    },\n                    {\n                        path: 'menu1-2',\n                        component: () => import('@/views/nested/menu1/menu1-2/index.vue'),\n                        name: 'Menu1-2',\n                        meta: { title: 'Menu1-2' },\n                        children: [\n                            {\n                                path: 'menu1-2-1',\n                                component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1/index.vue'),\n                                name: 'Menu1-2-1',\n                                meta: { title: 'Menu1-2-1' }\n                            },\n                            {\n                                path: 'menu1-2-2',\n                                component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2/index.vue'),\n                                name: 'Menu1-2-2',\n                                meta: { title: 'Menu1-2-2' }\n                            }\n                        ]\n                    },\n                    {\n                        path: 'menu1-3',\n                        component: () => import('@/views/nested/menu1/menu1-3/index.vue'),\n                        name: 'Menu1-3',\n                        meta: { title: 'Menu1-3' }\n                    }\n                ]\n            },\n            {\n                path: 'menu2',\n                component: () => import('@/views/nested/menu2/index.vue'),\n                name: 'Menu2',\n                meta: { title: 'menu2' }\n            }\n        ]\n    },\n    {\n        path: '/external-link',\n        component: Layout,\n        children: [\n            {\n                component: () => { },\n                path: 'https://github.com/jzfai/vue3-admin-ts.git',\n                meta: { title: 'External Link', icon: 'link' }\n            }\n        ]\n    }\n];\nexport const roleCodeRoutes = [\n    {\n        path: '/roles-codes',\n        component: Layout,\n        redirect: '/roles-codes/page',\n        alwaysShow: true,\n        name: 'Permission',\n        meta: {\n            title: 'Permission',\n            icon: 'lock',\n            roles: ['admin', 'editor']\n        },\n        children: [\n            {\n                path: 'index',\n                component: () => import('@/views/roles-codes/index.vue'),\n                name: 'RolesCodes',\n                meta: {\n                    title: 'index'\n                }\n            },\n            {\n                path: 'roleIndex',\n                component: () => import('@/views/roles-codes/role-index.vue'),\n                name: 'RoleIndex',\n                meta: {\n                    title: 'Role Index',\n                    roles: ['admin']\n                }\n            },\n            {\n                path: 'code-index',\n                component: () => import('@/views/roles-codes/code-index.vue'),\n                name: 'CodeIndex',\n                meta: {\n                    title: 'Code Index',\n                    code: 16\n                }\n            },\n            {\n                path: 'button-permission',\n                component: () => import('@/views/roles-codes/button-permission.vue'),\n                name: 'ButtonPermission',\n                meta: {\n                    title: 'Button Permission'\n                }\n            }\n        ]\n    }\n];\nexport const asyncRoutes = [\n    { path: '/:catchAll(.*)', name: 'CatchAll', redirect: '/404', hidden: true }\n];\nconst router = createRouter({\n    history: createWebHashHistory(),\n    scrollBehavior: () => ({ top: 0 }),\n    routes: constantRoutes\n});\nexport default router;\n"
  },
  {
    "path": "ts-out-dir/src/settings.d.ts",
    "content": "import type { SettingsConfig } from '~/basic';\ndeclare const settings: SettingsConfig;\nexport default settings;\n"
  },
  {
    "path": "ts-out-dir/src/settings.js",
    "content": "const settings = {\n    title: 'Vue3 Admin Template',\n    sidebarLogo: true,\n    showNavbarTitle: false,\n    ShowDropDown: true,\n    showHamburger: true,\n    showLeftMenu: true,\n    showTagsView: true,\n    tagsViewNum: 6,\n    showTopNavbar: true,\n    mainNeedAnimation: true,\n    isNeedNprogress: true,\n    isNeedLogin: true,\n    permissionMode: 'roles',\n    openProdMock: true,\n    errorLog: ['prod'],\n    delWindowHeight: '210px',\n    tmpToken: 'tmp_token',\n    viteBasePath: './'\n};\nexport default settings;\n"
  },
  {
    "path": "ts-out-dir/src/store/basic.d.ts",
    "content": "import type { RouterTypes } from '~/basic';\nexport declare const useBasicStore: import(\"pinia\").StoreDefinition<\"basic\", {\n    token: string;\n    getUserInfo: boolean;\n    userInfo: {\n        username: string;\n        avatar: string;\n    };\n    allRoutes: RouterTypes;\n    buttonCodes: never[];\n    filterAsyncRoutes: never[];\n    roles: string[];\n    codes: number[];\n    cachedViews: string[];\n    cachedViewsDeep: string[];\n    sidebar: {\n        opened: boolean;\n    };\n    axiosPromiseArr: ObjKeys[];\n    settings: import(\"~/basic\").SettingsConfig;\n}, {}, {\n    setToken(data: any): void;\n    setFilterAsyncRoutes(routes: any): void;\n    setUserInfo({ userInfo, roles, codes }: {\n        userInfo: any;\n        roles: any;\n        codes: any;\n    }): void;\n    resetState(): void;\n    resetStateAndToLogin(): void;\n    M_settings(data: any): void;\n    setSidebarOpen(data: any): void;\n    setToggleSideBar(): void;\n    addCachedView(view: any): void;\n    delCachedView(view: any): void;\n    M_RESET_CACHED_VIEW(): void;\n    addCachedViewDeep(view: any): void;\n    setCacheViewDeep(view: any): void;\n    M_RESET_CACHED_VIEW_DEEP(): void;\n    A_sidebar_opened(data: any): void;\n}>;\n"
  },
  {
    "path": "ts-out-dir/src/store/basic.js",
    "content": "import { nextTick } from 'vue';\nimport { defineStore } from 'pinia';\nimport defaultSettings from '@/settings';\nimport router, { constantRoutes } from '@/router';\nexport const useBasicStore = defineStore('basic', {\n    state: () => {\n        return {\n            token: '',\n            getUserInfo: false,\n            userInfo: {\n                username: '',\n                avatar: ''\n            },\n            allRoutes: [],\n            buttonCodes: [],\n            filterAsyncRoutes: [],\n            roles: [],\n            codes: [],\n            cachedViews: [],\n            cachedViewsDeep: [],\n            sidebar: { opened: true },\n            axiosPromiseArr: [],\n            settings: defaultSettings\n        };\n    },\n    persist: {\n        storage: localStorage,\n        paths: ['token']\n    },\n    actions: {\n        setToken(data) {\n            this.token = data;\n        },\n        setFilterAsyncRoutes(routes) {\n            this.$patch((state) => {\n                state.filterAsyncRoutes = routes;\n                state.allRoutes = constantRoutes.concat(routes);\n            });\n        },\n        setUserInfo({ userInfo, roles, codes }) {\n            const { username, avatar } = userInfo;\n            this.$patch((state) => {\n                state.roles = roles;\n                state.codes = codes;\n                state.getUserInfo = true;\n                state.userInfo.username = username;\n                state.userInfo.avatar = avatar;\n            });\n        },\n        resetState() {\n            this.$patch((state) => {\n                state.token = '';\n                state.roles = [];\n                state.codes = [];\n                state.allRoutes = [];\n                state.buttonCodes = [];\n                state.filterAsyncRoutes = [];\n                state.userInfo.username = '';\n                state.userInfo.avatar = '';\n            });\n            this.getUserInfo = false;\n        },\n        resetStateAndToLogin() {\n            this.resetState();\n            nextTick(() => {\n                router.push({ path: '/login' });\n            });\n        },\n        M_settings(data) {\n            this.$patch((state) => {\n                state.settings = { ...state.settings, ...data };\n            });\n        },\n        setSidebarOpen(data) {\n            this.$patch((state) => {\n                state.sidebar.opened = data;\n            });\n        },\n        setToggleSideBar() {\n            this.$patch((state) => {\n                state.sidebar.opened = !state.sidebar.opened;\n            });\n        },\n        addCachedView(view) {\n            this.$patch((state) => {\n                if (state.cachedViews.includes(view))\n                    return;\n                state.cachedViews.push(view);\n            });\n        },\n        delCachedView(view) {\n            this.$patch((state) => {\n                const index = state.cachedViews.indexOf(view);\n                index > -1 && state.cachedViews.splice(index, 1);\n            });\n        },\n        M_RESET_CACHED_VIEW() {\n            this.$patch((state) => {\n                state.cachedViews = [];\n            });\n        },\n        addCachedViewDeep(view) {\n            this.$patch((state) => {\n                if (state.cachedViewsDeep.includes(view))\n                    return;\n                state.cachedViewsDeep.push(view);\n            });\n        },\n        setCacheViewDeep(view) {\n            this.$patch((state) => {\n                const index = state.cachedViewsDeep.indexOf(view);\n                index > -1 && state.cachedViewsDeep.splice(index, 1);\n            });\n        },\n        M_RESET_CACHED_VIEW_DEEP() {\n            this.$patch((state) => {\n                state.cachedViewsDeep = [];\n            });\n        },\n        A_sidebar_opened(data) {\n            this.setSidebarOpen(data);\n        }\n    }\n});\n"
  },
  {
    "path": "ts-out-dir/src/store/tagsView.d.ts",
    "content": "export declare const useTagsViewStore: import(\"pinia\").StoreDefinition<\"tagsView\", {\n    visitedViews: never[];\n}, {}, {\n    addVisitedView(view: any): void;\n    delVisitedView(view: any): Promise<unknown>;\n    delOthersVisitedViews(view: any): Promise<unknown>;\n    delAllVisitedViews(): Promise<unknown>;\n}>;\n"
  },
  {
    "path": "ts-out-dir/src/store/tagsView.js",
    "content": "import { defineStore } from 'pinia';\nimport setting from '@/settings';\nexport const useTagsViewStore = defineStore('tagsView', {\n    state: () => {\n        return {\n            visitedViews: []\n        };\n    },\n    actions: {\n        addVisitedView(view) {\n            this.$patch((state) => {\n                if (state.visitedViews.some((v) => v.path === view.path))\n                    return;\n                if (state.visitedViews.length >= setting.tagsViewNum) {\n                    state.visitedViews.pop();\n                    state.visitedViews.push(Object.assign({}, view, {\n                        title: view.meta.title || 'no-name'\n                    }));\n                }\n                else {\n                    state.visitedViews.push(Object.assign({}, view, {\n                        title: view.meta.title || 'no-name'\n                    }));\n                }\n            });\n        },\n        delVisitedView(view) {\n            return new Promise((resolve) => {\n                this.$patch((state) => {\n                    for (const [i, v] of state.visitedViews.entries()) {\n                        if (v.path === view.path) {\n                            state.visitedViews.splice(i, 1);\n                            break;\n                        }\n                    }\n                    resolve([...state.visitedViews]);\n                });\n            });\n        },\n        delOthersVisitedViews(view) {\n            return new Promise((resolve) => {\n                this.$patch((state) => {\n                    state.visitedViews = state.visitedViews.filter((v) => {\n                        return v.meta.affix || v.path === view.path;\n                    });\n                    resolve([...state.visitedViews]);\n                });\n            });\n        },\n        delAllVisitedViews() {\n            return new Promise((resolve) => {\n                this.$patch((state) => {\n                    state.visitedViews = state.visitedViews.filter((tag) => tag.meta?.affix);\n                    resolve([...state.visitedViews]);\n                });\n            });\n        }\n    }\n});\n"
  },
  {
    "path": "ts-out-dir/src/utils/axios-req.d.ts",
    "content": "export default function axiosReq(config: any): import(\"axios\").AxiosPromise<any>;\n"
  },
  {
    "path": "ts-out-dir/src/utils/axios-req.js",
    "content": "import axios from 'axios';\nimport { ElMessage, ElMessageBox } from 'element-plus';\nimport { useBasicStore } from '@/store/basic';\nconst service = axios.create();\nservice.interceptors.request.use((req) => {\n    const { token, axiosPromiseArr } = useBasicStore();\n    req.cancelToken = new axios.CancelToken((cancel) => {\n        axiosPromiseArr.push({\n            url: req.url,\n            cancel\n        });\n    });\n    req.headers['AUTHORIZE_TOKEN'] = token;\n    if ('get'.includes(req.method?.toLowerCase()))\n        req.params = req.data;\n    return req;\n}, (err) => {\n    Promise.reject(err);\n});\nservice.interceptors.response.use((res) => {\n    const { code } = res.data;\n    const successCode = '0,200,20000';\n    const noAuthCode = '401,403';\n    if (successCode.includes(code)) {\n        return res.data;\n    }\n    else {\n        if (noAuthCode.includes(code) && !location.href.includes('/login')) {\n            ElMessageBox.confirm('请重新登录', {\n                confirmButtonText: '重新登录',\n                cancelButtonText: '取消',\n                type: 'warning'\n            }).then(() => {\n                useBasicStore().resetStateAndToLogin();\n            });\n        }\n        return Promise.reject(res.data);\n    }\n}, (err) => {\n    ElMessage.error({\n        message: err,\n        duration: 2 * 1000\n    });\n    return Promise.reject(err);\n});\nexport default function axiosReq(config) {\n    return service({\n        baseURL: import.meta.env.VITE_APP_BASE_URL,\n        timeout: 8000,\n        ...config\n    });\n}\n"
  },
  {
    "path": "ts-out-dir/src/utils/bus.d.ts",
    "content": "declare const _default: import(\"mitt\").Emitter<Record<import(\"mitt\").EventType, unknown>>;\nexport default _default;\n"
  },
  {
    "path": "ts-out-dir/src/utils/bus.js",
    "content": "import mitt from 'mitt';\nexport default mitt();\n"
  },
  {
    "path": "ts-out-dir/src/utils/common-util.d.ts",
    "content": "declare const _default: {\n    getWeek(): string;\n    mobilePhone(str: any): boolean;\n    toSplitNumFor(num: any, numToSpace: any): any;\n    bankCardNo(str: any): boolean;\n    regEmail(str: any): boolean;\n    idCardNumber(str: any): boolean;\n    deleteArrItem(arr: any, arrItem: any): void;\n    arrToRepeat(arr: any): any;\n    deRepeatArr(seriesArr: any): unknown[];\n    byArrObjDeleteArrObj2(arrObj: any, arrObj2: any, objKey: any): any;\n    deleteArrObjByKey(arrObj: any, objKey: any, value: any): any;\n    findArrObjByKey(arrObj: any, objKey: any, value: any): any;\n    byArrObjFindArrObj2(arrObj: any, arrObj2: any, objKey: any): any[];\n};\nexport default _default;\n"
  },
  {
    "path": "ts-out-dir/src/utils/common-util.js",
    "content": "export default {\n    getWeek() {\n        return `星期${'日一二三四五六'.charAt(new Date().getDay())}`;\n    },\n    mobilePhone(str) {\n        const reg = /^0?1[0-9]{10}$/;\n        return reg.test(str);\n    },\n    toSplitNumFor(num, numToSpace) {\n        return num.replace(/(.{4})/g, '$1 ');\n    },\n    bankCardNo(str) {\n        const reg = /^\\d{15,20}$/;\n        return reg.test(str);\n    },\n    regEmail(str) {\n        const reg = /^([a-zA-Z]|[0-9])(\\w|-)+@[a-zA-Z0-9]+\\.([a-zA-Z]{2,4})$/;\n        return reg.test(str);\n    },\n    idCardNumber(str) {\n        const reg = /(^\\d{15}$)|(^\\d{18}$)|(^\\d{17}(\\d|X|x)$)/;\n        return reg.test(str);\n    },\n    deleteArrItem(arr, arrItem) {\n        arr.splice(arr.indexOf(arrItem), 1);\n    },\n    arrToRepeat(arr) {\n        return arr.filter((ele, index, thisArr) => {\n            return thisArr.indexOf(ele) === index;\n        });\n    },\n    deRepeatArr(seriesArr) {\n        return [...new Set(seriesArr)];\n    },\n    byArrObjDeleteArrObj2(arrObj, arrObj2, objKey) {\n        arrObj\n            .map((value) => {\n            return value[objKey];\n        })\n            .forEach((value2) => {\n            arrObj2.splice(arrObj2.findIndex((item) => item[objKey] === value2), 1);\n        });\n        return arrObj2;\n    },\n    deleteArrObjByKey(arrObj, objKey, value) {\n        arrObj.splice(arrObj.findIndex((item) => item[objKey] === value), 1);\n        return arrObj;\n    },\n    findArrObjByKey(arrObj, objKey, value) {\n        return arrObj[arrObj.findIndex((item) => item[objKey] == value)];\n    },\n    byArrObjFindArrObj2(arrObj, arrObj2, objKey) {\n        const arrObj3 = [];\n        arrObj\n            .map((value) => {\n            return value[objKey];\n        })\n            .forEach((value2) => {\n            const arrIndex = arrObj2.findIndex((item) => item[objKey] === value2);\n            if (arrIndex !== -1) {\n                arrObj3.push(arrObj2[arrIndex]);\n            }\n        });\n        return arrObj3;\n    }\n};\n"
  },
  {
    "path": "ts-out-dir/src/views/redirect/index.d.ts",
    "content": "declare const _default: import(\"vue\").DefineComponent<{}, () => JSX.Element, {}, {}, {}, import(\"vue\").ComponentOptionsMixin, import(\"vue\").ComponentOptionsMixin, {}, string, import(\"vue\").VNodeProps & import(\"vue\").AllowedComponentProps & import(\"vue\").ComponentCustomProps, Readonly<import(\"vue\").ExtractPropTypes<{}>>, {}>;\nexport default _default;\n"
  },
  {
    "path": "ts-out-dir/src/views/redirect/index.jsx",
    "content": "import { defineComponent } from 'vue';\nexport default defineComponent({\n    setup() {\n        const route = useRoute();\n        const router = useRouter();\n        onBeforeMount(() => {\n            const { params, query } = route;\n            const { path } = params;\n            router.replace({ path: `/${path}`, query });\n        });\n        return () => <div> </div>;\n    }\n});\n"
  },
  {
    "path": "tsconfig.base.json",
    "content": "{\n  //设置files为空,则不会自动扫描默认目录，也就是只会扫描include配置的目录\n  \"files\": [],\n  \"compilerOptions\": {\n    \"target\": \"esnext\",\n    \"module\": \"esnext\",\n    //启用所有严格类型检查选项。\n    //启用 --strict相当于启用 --noImplicitAny, --noImplicitThis, --alwaysStrict， --strictNullChecks和 --strictFunctionTypes和--strictPropertyInitialization。\n    \"strict\": true,\n    // 允许编译器编译JS，JSX文件\n    \"allowJs\": false,\n    // 允许在JS文件中报错，通常与allowJS一起使用\n    \"checkJs\": false,\n    // 允许使用jsx\n    \"jsx\": \"preserve\",\n    \"declaration\": true,\n    //移除注解\n    \"removeComments\": true,\n    //不可以忽略any\n    \"noImplicitAny\": false,\n    //关闭 this 类型注解提示\n    \"noImplicitThis\": true,\n    //null/undefined不能作为其他类型的子类型：\n    //let a: number = null; //这里会报错.\n    \"strictNullChecks\": true,\n    //生成枚举的映射代码\n    \"preserveConstEnums\": true,\n    //根目录\n    //输出目录\n    \"outDir\": \"./ts-out-dir\",\n    //是否输出src2.js.map文件\n    \"sourceMap\": false,\n    //变量定义了但是未使用\n    \"noUnusedLocals\": false,\n    //是否允许把json文件当做模块进行解析\n    \"resolveJsonModule\": true,\n    //和noUnusedLocals一样，针对func\n    \"noUnusedParameters\": false,\n    // 模块解析策略，ts默认用node的解析策略，即相对的方式导入\n    \"moduleResolution\": \"node\",\n    //允许export=导出，由import from 导入\n    \"esModuleInterop\": true,\n    //忽略所有的声明文件（ *.d.ts）的类型检查。\n    \"skipLibCheck\": true,\n    \"baseUrl\": \".\",\n    //指定默认读取的目录\n    //\"typeRoots\": [\"./node_modules/@types/\", \"./types\"],\n    \"lib\": [\"ES2018\", \"DOM\"]\n  }\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"extends\": \"./tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"paths\": {\n      \"@/*\": [\"src/*\"],\n      \"~/*\": [\"typings/*\"]\n    }\n  },\n  \"include\": [\"src\", \"typings\"],\n  \"exclude\": [\"node_modules\", \"**/dist\"]\n}\n"
  },
  {
    "path": "typings/auto-imports.d.ts",
    "content": "// Generated by 'unplugin-auto-import'\nexport {}\ndeclare global {\n  const EffectScope: typeof import('vue')['EffectScope']\n  const axiosReq: typeof import('../src/utils/axios-req')['default']\n  const bus: typeof import('../src/utils/bus')['default']\n  const buttonCodes: typeof import('../src/directives/button-codes')['default']\n  const casHandleChange: typeof import('../src/hooks/use-element')['casHandleChange']\n  const cloneDeep: typeof import('../src/hooks/use-common')['cloneDeep']\n  const closeElLoading: typeof import('../src/hooks/use-element')['closeElLoading']\n  const codesPermission: typeof import('../src/directives/codes-permission')['default']\n  const commonUtil: typeof import('../src/utils/common-util')['default']\n  const computed: typeof import('vue')['computed']\n  const copyValueToClipboard: typeof import('../src/hooks/use-common')['copyValueToClipboard']\n  const createApp: typeof import('vue')['createApp']\n  const customRef: typeof import('vue')['customRef']\n  const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']\n  const defineComponent: typeof import('vue')['defineComponent']\n  const directives: typeof import('../src/directives/index')['default']\n  const effectScope: typeof import('vue')['effectScope']\n  const elConfirm: typeof import('../src/hooks/use-element')['elConfirm']\n  const elConfirmNoCancelBtn: typeof import('../src/hooks/use-element')['elConfirmNoCancelBtn']\n  const elLoading: typeof import('../src/hooks/use-element')['elLoading']\n  const elMessage: typeof import('../src/hooks/use-element')['elMessage']\n  const elNotify: typeof import('../src/hooks/use-element')['elNotify']\n  const filterAsyncRouter: typeof import('../src/hooks/use-permission')['filterAsyncRouter']\n  const filterAsyncRouterByCodes: typeof import('../src/hooks/use-permission')['filterAsyncRouterByCodes']\n  const filterAsyncRoutesByMenuList: typeof import('../src/hooks/use-permission')['filterAsyncRoutesByMenuList']\n  const filterAsyncRoutesByRoles: typeof import('../src/hooks/use-permission')['filterAsyncRoutesByRoles']\n  const freshRouter: typeof import('../src/hooks/use-permission')['freshRouter']\n  const getCurrentInstance: typeof import('vue')['getCurrentInstance']\n  const getCurrentScope: typeof import('vue')['getCurrentScope']\n  const getLangInstance: typeof import('../src/hooks/use-common')['getLangInstance']\n  const getQueryParam: typeof import('../src/hooks/use-self-router')['getQueryParam']\n  const h: typeof import('vue')['h']\n  const inject: typeof import('vue')['inject']\n  const isExternal: typeof import('../src/hooks/use-layout')['isExternal']\n  const isProxy: typeof import('vue')['isProxy']\n  const isReactive: typeof import('vue')['isReactive']\n  const isReadonly: typeof import('vue')['isReadonly']\n  const isRef: typeof import('vue')['isRef']\n  const lang: typeof import('../src/directives/lang')['default']\n  const langTitle: typeof import('../src/hooks/use-common')['langTitle']\n  const markRaw: typeof import('vue')['markRaw']\n  const nextTick: typeof import('vue')['nextTick']\n  const onActivated: typeof import('vue')['onActivated']\n  const onBeforeMount: typeof import('vue')['onBeforeMount']\n  const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']\n  const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']\n  const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']\n  const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']\n  const onDeactivated: typeof import('vue')['onDeactivated']\n  const onErrorCaptured: typeof import('vue')['onErrorCaptured']\n  const onMounted: typeof import('vue')['onMounted']\n  const onRenderTracked: typeof import('vue')['onRenderTracked']\n  const onRenderTriggered: typeof import('vue')['onRenderTriggered']\n  const onScopeDispose: typeof import('vue')['onScopeDispose']\n  const onServerPrefetch: typeof import('vue')['onServerPrefetch']\n  const onUnmounted: typeof import('vue')['onUnmounted']\n  const onUpdated: typeof import('vue')['onUpdated']\n  const progressClose: typeof import('../src/hooks/use-permission')['progressClose']\n  const progressStart: typeof import('../src/hooks/use-permission')['progressStart']\n  const provide: typeof import('vue')['provide']\n  const reactive: typeof import('vue')['reactive']\n  const readonly: typeof import('vue')['readonly']\n  const ref: typeof import('vue')['ref']\n  const resetRouter: typeof import('../src/hooks/use-permission')['resetRouter']\n  const resetState: typeof import('../src/hooks/use-permission')['resetState']\n  const resizeHandler: typeof import('../src/hooks/use-layout')['resizeHandler']\n  const resolveComponent: typeof import('vue')['resolveComponent']\n  const resolveDirective: typeof import('vue')['resolveDirective']\n  const rolesPermission: typeof import('../src/directives/roles-permission')['default']\n  const routeInfo: typeof import('../src/hooks/use-self-router')['routeInfo']\n  const routerBack: typeof import('../src/hooks/use-self-router')['routerBack']\n  const routerPush: typeof import('../src/hooks/use-self-router')['routerPush']\n  const routerReplace: typeof import('../src/hooks/use-self-router')['routerReplace']\n  const shallowReactive: typeof import('vue')['shallowReactive']\n  const shallowReadonly: typeof import('vue')['shallowReadonly']\n  const shallowRef: typeof import('vue')['shallowRef']\n  const sleepTimeout: typeof import('../src/hooks/use-common')['sleepTimeout']\n  const storeToRefs: typeof import('pinia/dist/pinia')['storeToRefs']\n  const toRaw: typeof import('vue')['toRaw']\n  const toRef: typeof import('vue')['toRef']\n  const toRefs: typeof import('vue')['toRefs']\n  const triggerRef: typeof import('vue')['triggerRef']\n  const unref: typeof import('vue')['unref']\n  const useAttrs: typeof import('vue')['useAttrs']\n  const useBasicStore: typeof import('../src/store/basic')['useBasicStore']\n  const useConfigStore: typeof import('../src/store/config')['useConfigStore']\n  const useCssModule: typeof import('vue')['useCssModule']\n  const useCssVars: typeof import('vue')['useCssVars']\n  const useElement: typeof import('../src/hooks/use-element')['useElement']\n  const useErrorLog: typeof import('../src/hooks/use-error-log')['useErrorLog']\n  const useLink: typeof import('vue-router')['useLink']\n  const useRoute: typeof import('vue-router')['useRoute']\n  const useRouter: typeof import('vue-router')['useRouter']\n  const useSlots: typeof import('vue')['useSlots']\n  const useTable: typeof import('../src/hooks/use-table')['useTable']\n  const useTagsViewStore: typeof import('../src/store/tags-view')['useTagsViewStore']\n  const watch: typeof import('vue')['watch']\n  const watchEffect: typeof import('vue')['watchEffect']\n  const watchPostEffect: typeof import('vue')['watchPostEffect']\n  const watchSyncEffect: typeof import('vue')['watchSyncEffect']\n}\n"
  },
  {
    "path": "typings/basic.d.ts",
    "content": "/*\n * 声明.d.ts文件规范\n * 导出的类型以大写开头\n * 对象：config\n * 数组：options\n * 枚举：emu\n * 函数：Fn\n * 属性：props\n * 实例：instance\n * */\n\n/*router*/\nimport type { RouteRecordRaw } from 'vue-router'\nexport interface rawConfig {\n  hidden?: boolean\n  alwaysShow?: boolean\n  code?: number\n  name?: string\n  fullPath?: string\n  path?: string\n  meta?: {\n    title: string\n    icon?: string\n    affix?: boolean\n    activeMenu?: string\n    breadcrumb?: boolean\n    roles?: Array<string>\n    elSvgIcon?: string\n    code?: number\n    cachePage?: boolean\n    leaveRmCachePage?: boolean\n    closeTabRmCache?: boolean\n  }\n  children?: RouterOptions\n  redirect?: string\n}\nexport type RouteRawConfig = RouteRecordRaw & rawConfig\nexport type RouterTypes = Array<rawProp>\n\n/*settings*/\nexport interface SettingsConfig {\n  title: string\n  sidebarLogo: boolean\n  showLeftMenu: boolean\n  ShowDropDown: boolean\n  showHamburger: boolean\n  isNeedLogin: boolean\n  isNeedNprogress: boolean\n  showTagsView: boolean\n  tagsViewNum: number\n  openProdMock: boolean\n  errorLog: string | Array<string>\n  permissionMode: string\n  delWindowHeight: string\n  tmpToken: string\n  showNavbarTitle: boolean\n  showTopNavbar: boolean\n  mainNeedAnimation: boolean\n  viteBasePath: string\n  defaultLanguage: string\n  defaultSize: string\n  defaultTheme: string\n  plateFormId: number\n}\n\nexport {}\n"
  },
  {
    "path": "typings/components.d.ts",
    "content": "// generated by unplugin-vue-components\n// We suggest you to commit this file into source control\n// Read more: https://github.com/vuejs/core/pull/3399\nimport '@vue/runtime-core'\n\nexport {}\n\ndeclare module '@vue/runtime-core' {\n  export interface GlobalComponents {\n    ElSvgIcon: typeof import('./../src/components/ElSvgIcon.vue')['default']\n    RouterLink: typeof import('vue-router')['RouterLink']\n    RouterView: typeof import('vue-router')['RouterView']\n    SvgIcon: typeof import('./../src/icons/SvgIcon.vue')['default']\n    TestUnit: typeof import('./../src/components/TestUnit.vue')['default']\n  }\n}\n"
  },
  {
    "path": "typings/env.d.ts",
    "content": "declare global {\n  interface ImportMetaEnv {\n    readonly VITE_APP_BASE_URL: string\n    readonly VITE_APP_IMAGE_URL: string\n    readonly VITE_APP_ENV: string\n    // 更多环境变量...\n  }\n  interface ImportMeta {\n    readonly env: ImportMetaEnv\n  }\n}\nexport {}\n"
  },
  {
    "path": "typings/global.d.ts",
    "content": "import type { defineOptions as _defineOptions } from 'unplugin-vue-define-options/macros.d.ts'\ndeclare global {\n  interface ObjKeys {\n    [propName: string]: any\n  }\n  const GLOBAL_VAR: String\n  const defineOptions: typeof _defineOptions\n  const $ref: any\n}\nexport {}\n"
  },
  {
    "path": "typings/shims-vue.d.ts",
    "content": "/*fix the import warning issue of vue file*/\ndeclare module '*.vue' {\n  import { DefineComponent } from 'vue'\n  const component: DefineComponent<{}, {}, any>\n  export default component\n}\n"
  },
  {
    "path": "vite.config.ts",
    "content": "import { resolve } from 'path'\nimport { defineConfig, loadEnv } from 'vite'\nimport vue from '@vitejs/plugin-vue'\nimport vueJsx from '@vitejs/plugin-vue-jsx'\nimport { createSvgIconsPlugin } from 'vite-plugin-svg-icons'\nimport { viteMockServe } from 'vite-plugin-mock'\nimport Components from 'unplugin-vue-components/vite'\nimport UnoCSS from 'unocss/vite'\nimport { presetAttributify, presetIcons, presetUno } from 'unocss'\nimport mkcert from 'vite-plugin-mkcert'\nimport AutoImport from 'unplugin-auto-import/vite'\nimport setting from './src/settings'\nimport vitePluginSetupExtend from './src/plugins/vite-plugin-setup-extend'\nconst prodMock = setting.openProdMock\n// import { visualizer } from 'rollup-plugin-visualizer'\nconst pathSrc = resolve(__dirname, 'src')\n// @ts-ignore\nexport default defineConfig(({ command, mode }) => {\n  //const env = loadEnv(mode, process.cwd(), '') //获取环境变量\n  return {\n    base: setting.viteBasePath,\n    define: {\n      //define global var\n      GLOBAL_STRING: JSON.stringify('i am global var from vite.config.js define'),\n      GLOBAL_VAR: { test: 'i am global var from vite.config.js define' }\n    },\n    clearScreen: false, //设为 false 可以避免 Vite 清屏而错过在终端中打印某些关键信息\n    server: {\n      hmr: { overlay: false }, //设置 server.hmr.overlay 为 false 可以禁用开发服务器错误的屏蔽。方便错误查看\n      port: 5003, // 类型： number 指定服务器端口;\n      open: false, // 类型： boolean | string在服务器启动时自动在浏览器中打开应用程序；\n      host: true,\n      https: false\n    },\n    preview: {\n      port: 5006,\n      host: true,\n      strictPort: true\n    },\n    plugins: [\n      vue(),\n      vueJsx(),\n      UnoCSS({\n        presets: [presetUno(), presetAttributify(), presetIcons()]\n      }),\n      mkcert(),\n      //compatible with old browsers\n      // legacy({\n      //   targets: ['chrome 52'],\n      //   additionalLegacyPolyfills: ['regenerator-runtime/runtime']\n      // }),\n      createSvgIconsPlugin({\n        iconDirs: [resolve(process.cwd(), 'src/icons/common'), resolve(process.cwd(), 'src/icons/nav-bar')],\n        symbolId: 'icon-[dir]-[name]'\n      }),\n      //https://github.com/anncwb/vite-plugin-mock/blob/HEAD/README.zh_CN.md\n      viteMockServe({\n        enable:true,\n        mockPath: 'mock',\n        // prodEnabled: prodMock,\n        // injectCode: `\n        //   import { setupProdMockServer } from './mock-prod-server';\n        //   setupProdMockServer();\n        // `,\n        logger: true\n      }),\n      // VueSetupExtend(),using  DefineOptions instant of it\n      //https://github.com/antfu/unplugin-auto-import/blob/HEAD/src/types.ts\n      Components({\n        dirs: ['src/components', 'src/icons'],\n        extensions: ['vue'],\n        deep: true,\n        dts: './typings/components.d.ts'\n      }),\n      AutoImport({\n        imports: [\n          'vue',\n          'vue-router',\n          {\n            'pinia/dist/pinia': ['storeToRefs']\n          }\n        ],\n        //配置后会自动扫描目录下的文件\n        dirs: ['src/hooks/**', 'src/utils/**', 'src/store/**', 'src/directives/**'],\n        eslintrc: {\n          enabled: true, // Default `false`\n          filepath: './eslintrc/.eslintrc-auto-import.json', // Default `./.eslintrc-auto-import.json`\n          globalsPropValue: true // Default `true`, (true | false | 'readonly' | 'readable' | 'writable' | 'writeable')\n        },\n        dts: './typings/auto-imports.d.ts'\n      }),\n      // auto config of index.html title\n      //依赖分析插件\n      // visualizer({\n      //   open: true,\n\n      //   gzipSize: true,\n      //   brotliSize: true\n      // })\n      vitePluginSetupExtend({ inject: { title: setting.title } })\n    ],\n    build: {\n      chunkSizeWarningLimit: 10000, //消除触发警告的 chunk, 默认500k\n      assetsDir: 'static/assets',\n      rollupOptions: {\n        output: {\n          chunkFileNames: 'static/js/[name]-[hash].js',\n          entryFileNames: 'static/js/[name]-[hash].js',\n          assetFileNames: 'static/[ext]/[name]-[hash].[ext]'\n        }\n      }\n    },\n    resolve: {\n      alias: {\n        '@/': `${pathSrc}/`,\n        'vue-i18n': 'vue-i18n/dist/vue-i18n.cjs.js' //remove i18n waring\n      }\n    },\n    optimizeDeps: {\n      //include: [...optimizeDependencies,...optimizeElementPlus] //on-demand element-plus use this\n      include: ['moment-mini']\n    }\n  }\n})\n"
  },
  {
    "path": "vitest.config.ts",
    "content": "import { defineConfig } from 'vitest/config'\nimport Vue from '@vitejs/plugin-vue'\nimport VueJsx from '@vitejs/plugin-vue-jsx'\nimport DefineOptions from 'unplugin-vue-define-options/vite'\n\nexport default defineConfig({\n  // @ts-ignore\n  plugins: [Vue(), VueJsx(), DefineOptions()],\n  optimizeDeps: {\n    disabled: true\n  },\n  test: {\n    clearMocks: true,\n    environment: 'jsdom',\n    //setup 文件的路径。它们将运行在每个测试文件之前。\n    setupFiles: ['./vitest.setup.ts'],\n    transformMode: {\n      web: [/\\.[jt]sx$/]\n    }\n  }\n})\n"
  },
  {
    "path": "vitest.setup.ts",
    "content": "import { config } from '@vue/test-utils'\nimport { vi } from 'vitest'\nimport ResizeObserver from 'resize-observer-polyfill'\n\nvi.stubGlobal('ResizeObserver', ResizeObserver)\n\nconfig.global.stubs = {}\n"
  }
]