├── .editorconfig ├── .env ├── .env.development ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .husky ├── commit-msg ├── pre-commit └── prepare-commit-msg ├── .npmrc ├── .prettierrc.js ├── .stylelintignore ├── .vscode ├── extensions.json └── settings.json ├── LICENSE ├── README.md ├── build └── vite │ ├── mock.ts │ └── proxy.ts ├── commitlint.config.js ├── docs └── starter.png ├── index.html ├── mock └── system │ ├── client.ts │ ├── dept.ts │ ├── dict.ts │ ├── dictbiz.ts │ ├── menu.ts │ ├── param.ts │ ├── post.ts │ ├── role.ts │ ├── tenant.ts │ └── user.ts ├── package-lock.json ├── package.json ├── public └── favicon.ico ├── src ├── App.vue ├── api │ ├── authority │ │ ├── apiscope.ts │ │ └── datascope.ts │ ├── base │ │ └── region.ts │ ├── flow │ │ └── flow.ts │ ├── log │ │ ├── api.ts │ │ ├── error.ts │ │ └── usual.ts │ ├── model │ │ ├── baseModel.ts │ │ ├── detailModel.ts │ │ ├── listModel.ts │ │ └── permissionModel.ts │ ├── process │ │ ├── leave.ts │ │ └── process.ts │ ├── resource │ │ ├── attach.ts │ │ ├── model │ │ │ └── ossModel.ts │ │ ├── oss.ts │ │ └── sms.ts │ ├── system │ │ ├── client.ts │ │ ├── dept.ts │ │ ├── dict.ts │ │ ├── dictbiz.ts │ │ ├── menu.ts │ │ ├── model │ │ │ ├── deptModel.ts │ │ │ ├── menuModel.ts │ │ │ ├── uploadModel.ts │ │ │ └── userModel.ts │ │ ├── param.ts │ │ ├── post.ts │ │ ├── role.ts │ │ ├── tenant.ts │ │ ├── tenantPackage.ts │ │ ├── topmenu.ts │ │ └── user.ts │ ├── tool │ │ └── datasource.ts │ └── work │ │ └── work.ts ├── assets │ ├── assets-empty.svg │ ├── assets-layout-mix.svg │ ├── assets-layout-side.svg │ ├── assets-layout-top.svg │ ├── assets-login-bg-black.png │ ├── assets-login-bg-white.png │ ├── assets-logo-full.svg │ ├── assets-picked.svg │ ├── assets-result-403.svg │ ├── assets-result-404.svg │ ├── assets-result-500.svg │ ├── assets-result-ie.svg │ ├── assets-result-maintenance.svg │ ├── assets-result-wifi.svg │ ├── assets-setting-auto.svg │ ├── assets-setting-dark.svg │ ├── assets-setting-icon.svg │ ├── assets-setting-light.svg │ ├── assets-slide-dashboard.svg │ ├── assets-slide-detail.svg │ ├── assets-slide-form.svg │ ├── assets-slide-list.svg │ ├── assets-slide-logout.svg │ ├── assets-t-logo.svg │ └── assets-tencent-logo.png ├── components │ ├── color │ │ └── index.vue │ ├── flow-image │ │ └── index.vue │ ├── result │ │ └── index.vue │ ├── thumbnail │ │ └── index.vue │ └── trend │ │ └── index.vue ├── config │ ├── color.ts │ ├── global.ts │ ├── proxy.ts │ ├── style.ts │ └── website.ts ├── constants │ └── index.ts ├── directives │ ├── index.ts │ └── permission.ts ├── hooks │ ├── event │ │ └── useWindowSizeFn.ts │ ├── index.ts │ ├── setting │ │ └── useSetting.ts │ └── web │ │ ├── useDesign.ts │ │ ├── usePermission.ts │ │ └── useRequset.ts ├── layouts │ ├── blank.vue │ ├── components │ │ ├── Breadcrumb.vue │ │ ├── Content.vue │ │ ├── Footer.vue │ │ ├── FrameBlank.vue │ │ ├── FrameContent.vue │ │ ├── Header.vue │ │ ├── LayoutContent.vue │ │ ├── LayoutHeader.vue │ │ ├── LayoutSideNav.vue │ │ ├── MenuContent.vue │ │ ├── Notice.vue │ │ ├── Search.vue │ │ ├── SelectSearch.vue │ │ └── SideNav.vue │ ├── frame │ │ ├── index.vue │ │ └── useFrameKeepAlive.ts │ ├── index.vue │ └── setting.vue ├── main.ts ├── mockProdServer.ts ├── pages │ ├── dashboard │ │ └── workbench │ │ │ └── index.vue │ ├── login │ │ ├── components │ │ │ ├── Header.vue │ │ │ ├── Login.vue │ │ │ └── Register.vue │ │ ├── index.less │ │ └── index.vue │ ├── redirect │ │ └── index.vue │ └── result │ │ ├── 403 │ │ └── index.vue │ │ ├── 404 │ │ └── index.vue │ │ ├── 500 │ │ └── index.vue │ │ ├── browser-incompatible │ │ └── index.vue │ │ ├── fail │ │ └── index.vue │ │ ├── maintenance │ │ └── index.vue │ │ ├── network-error │ │ └── index.vue │ │ └── success │ │ └── index.vue ├── permission.ts ├── router │ ├── constant.ts │ ├── helper │ │ ├── menuHelper.ts │ │ └── routeHelper.ts │ ├── index.ts │ ├── modules │ │ ├── base.ts │ │ ├── components.ts │ │ ├── others.ts │ │ └── process │ │ │ └── leava.ts │ └── types.ts ├── store │ ├── index.ts │ └── modules │ │ ├── dict.ts │ │ ├── notification.ts │ │ ├── permission.ts │ │ ├── setting.ts │ │ ├── tabs-router.ts │ │ └── user.ts ├── style │ ├── font-family.less │ ├── index.less │ ├── layout.less │ ├── reset.less │ └── variables.less ├── types │ ├── axios.d.ts │ ├── env.d.ts │ ├── globals.d.ts │ ├── index.d.ts │ ├── interface.d.ts │ └── vue-router.d.ts ├── utils │ ├── charts.ts │ ├── color.ts │ ├── date.ts │ ├── file │ │ ├── base64Conver.ts │ │ └── download.ts │ ├── helper │ │ ├── flowHelper.ts │ │ └── treeHelper.ts │ ├── index.ts │ ├── is.ts │ └── request │ │ ├── Axios.ts │ │ ├── AxiosCancel.ts │ │ ├── AxiosTransform.ts │ │ ├── checkStatus.ts │ │ ├── index.ts │ │ └── utils.ts ├── views │ ├── authority │ │ ├── apiscope.vue │ │ ├── datascope.vue │ │ └── role.vue │ ├── base │ │ └── region.vue │ ├── flow │ │ ├── deploy.vue │ │ ├── follow.vue │ │ ├── manager.vue │ │ └── model.vue │ ├── monitor │ │ └── log │ │ │ ├── api.vue │ │ │ ├── error.vue │ │ │ └── usual.vue │ ├── process │ │ └── leave │ │ │ ├── detail.vue │ │ │ ├── form.vue │ │ │ └── handle.vue │ ├── resource │ │ ├── attach.vue │ │ ├── oss.vue │ │ └── sms.vue │ ├── system │ │ ├── client.vue │ │ ├── dept.vue │ │ ├── dict.vue │ │ ├── dictbiz.vue │ │ ├── menu.vue │ │ ├── param.vue │ │ ├── post.vue │ │ ├── tenant.vue │ │ ├── topmenu.vue │ │ ├── user.vue │ │ └── userInfo.vue │ ├── tool │ │ └── datasource.vue │ └── work │ │ ├── claim.vue │ │ ├── done.vue │ │ ├── send.vue │ │ ├── start.vue │ │ └── todo.vue └── viewsBusiness │ ├── authority │ ├── components │ │ ├── apiscope │ │ │ ├── DialogAuthority.vue │ │ │ └── DialogForm.vue │ │ ├── datascope │ │ │ ├── DialogAuthority.vue │ │ │ └── DialogForm.vue │ │ └── role │ │ │ └── DialogForm.vue │ └── constant │ │ ├── apiscope │ │ ├── authority.ts │ │ └── constant.ts │ │ ├── datascope │ │ ├── authority.ts │ │ └── constant.ts │ │ └── role │ │ └── constant.ts │ ├── base │ └── components │ │ └── region │ │ └── DialogImport.vue │ ├── flow │ ├── components │ │ └── DialogDeploy.vue │ └── constant │ │ ├── follow │ │ └── constant.ts │ │ ├── manager │ │ └── constant.ts │ │ └── model │ │ └── constant.ts │ ├── monitor │ └── log │ │ ├── components │ │ ├── api │ │ │ └── DialogForm.vue │ │ ├── error │ │ │ └── DialogForm.vue │ │ └── usual │ │ │ └── DialogForm.vue │ │ └── constant │ │ ├── api │ │ └── constant.ts │ │ ├── error │ │ └── constant.ts │ │ └── usual │ │ └── constant.ts │ ├── resource │ ├── components │ │ ├── attach │ │ │ └── DialogUpload.vue │ │ ├── oss │ │ │ ├── DialogDebug.vue │ │ │ └── DialogForm.vue │ │ └── sms │ │ │ ├── DialogDebug.vue │ │ │ └── DialogForm.vue │ └── constant │ │ ├── attach │ │ └── constant.ts │ │ ├── oss │ │ └── constant.ts │ │ └── sms │ │ └── constant.ts │ ├── system │ ├── components │ │ ├── client │ │ │ └── DialogForm.vue │ │ ├── dept │ │ │ └── DialogForm.vue │ │ ├── dict │ │ │ ├── DialogForm.vue │ │ │ └── child │ │ │ │ ├── DialogForm.vue │ │ │ │ └── DialogList.vue │ │ ├── dictbiz │ │ │ ├── DialogForm.vue │ │ │ └── child │ │ │ │ ├── DialogForm.vue │ │ │ │ └── DialogList.vue │ │ ├── menu │ │ │ └── DialogForm.vue │ │ ├── param │ │ │ └── DialogForm.vue │ │ ├── post │ │ │ └── DialogForm.vue │ │ ├── tenant │ │ │ ├── DialogDatasource.vue │ │ │ ├── DialogForm.vue │ │ │ ├── DialogPackage.vue │ │ │ ├── DialogSetting.vue │ │ │ └── tenantPackage │ │ │ │ ├── DialogForm.vue │ │ │ │ └── DialogList.vue │ │ ├── topmenu │ │ │ └── DialogForm.vue │ │ └── user │ │ │ ├── DialogForm.vue │ │ │ ├── DialogImport.vue │ │ │ ├── DialogRole.vue │ │ │ └── platfrom │ │ │ ├── DialogForm.vue │ │ │ └── DialogList.vue │ └── constant │ │ ├── client │ │ └── constant.ts │ │ ├── dept │ │ └── constant.ts │ │ ├── dict │ │ ├── child │ │ │ └── constant.ts │ │ └── constant.ts │ │ ├── dictbiz │ │ ├── child │ │ │ └── constant.ts │ │ └── constant.ts │ │ ├── menu │ │ └── constant.ts │ │ ├── param │ │ └── constant.ts │ │ ├── post │ │ └── constant.ts │ │ ├── tenant │ │ ├── constant.ts │ │ └── tenantPackage │ │ │ └── constant.ts │ │ ├── topmenu │ │ └── constant.ts │ │ └── user │ │ ├── constant.ts │ │ └── platform.ts │ ├── tool │ ├── components │ │ └── datasource │ │ │ └── DialogForm.vue │ └── constant │ │ └── datasource │ │ └── constant.ts │ └── work │ └── constant │ ├── claim │ └── constant.ts │ ├── done │ └── constant.ts │ ├── send │ └── constant.ts │ ├── start │ └── constant.ts │ └── todo │ └── constant.ts ├── stylelint.config.js ├── tsconfig.json └── vite.config.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.md] 11 | trim_trailing_whitespace = false 12 | 13 | [*.{ts,js,vue,css}] 14 | indent_size = 2 15 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | # 打包路径 根据项目不同按需配置 2 | VITE_BASE_URL = ./ 3 | -------------------------------------------------------------------------------- /.env.development: -------------------------------------------------------------------------------- 1 | # 打包路径 2 | VITE_BASE_URL = ./ 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | snapshot* 2 | dist 3 | lib 4 | es 5 | esm 6 | node_modules 7 | src/_common 8 | static 9 | cypress 10 | script/test/cypress 11 | _site 12 | temp* 13 | static/ 14 | !.prettierrc.js -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | 4 | # build files 5 | es/ 6 | lib/ 7 | dist/ 8 | typings/ 9 | 10 | _site 11 | package 12 | tmp* 13 | temp* 14 | coverage 15 | test-report.html 16 | .idea/ 17 | yarn-error.log 18 | *.zip 19 | .history 20 | .stylelintcache 21 | 22 | .env.local 23 | .env.*.local 24 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | if [[ "$OS" == "Windows_NT" ]]; then 5 | npx.cmd --no-install commitlint -e $GIT_PARAMS 6 | else 7 | npx --no-install commitlint -e $GIT_PARAMS 8 | fi 9 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | if [[ "$OS" == "Windows_NT" ]]; then 5 | npx.cmd lint-staged 6 | else 7 | npx lint-staged 8 | fi 9 | -------------------------------------------------------------------------------- /.husky/prepare-commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | [[ "$(uname -a)" = *"MINGW64"* ]] && exit 0 3 | [ -n "$CI" ] && exit 0 4 | . "$(dirname "$0")/_/husky.sh" 5 | 6 | if [[ "$OS" == "Windows_NT" ]]; then 7 | exec < /dev/tty && npx.cmd git-cz --hook || true 8 | else 9 | exec < /dev/tty && npx git-cz --hook || true 10 | fi 11 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist = true 2 | hoist = true 3 | engine-strict =true 4 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // 一行最多 120 字符.. 3 | printWidth: 120, 4 | // 使用 2 个空格缩进 5 | tabWidth: 2, 6 | // 不使用缩进符,而使用空格 7 | useTabs: false, 8 | // 行尾需要有分号 9 | semi: true, 10 | // 使用单引号 11 | singleQuote: true, 12 | // 对象的 key 仅在必要时用引号 13 | quoteProps: 'as-needed', 14 | // jsx 不使用单引号,而使用双引号 15 | jsxSingleQuote: false, 16 | // 末尾需要有逗号 17 | trailingComma: 'all', 18 | // 大括号内的首尾需要空格 19 | bracketSpacing: true, 20 | // jsx 标签的反尖括号需要换行 21 | jsxBracketSameLine: false, 22 | // 箭头函数,只有一个参数的时候,也需要括号 23 | arrowParens: 'always', 24 | // 每个文件格式化的范围是文件的全部内容 25 | rangeStart: 0, 26 | rangeEnd: Infinity, 27 | // 不需要写文件开头的 @prettier 28 | requirePragma: false, 29 | // 不需要自动在文件开头插入 @prettier 30 | insertPragma: false, 31 | // 使用默认的折行标准 32 | proseWrap: 'preserve', 33 | // 根据显示样式决定 html 要不要折行 34 | htmlWhitespaceSensitivity: 'css', 35 | // vue 文件中的 script 和 style 内不用缩进 36 | vueIndentScriptAndStyle: false, 37 | // 换行符使用 auto 38 | endOfLine: 'auto', 39 | }; 40 | -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | # .stylelintignore 2 | # 旧的不需打包的样式库 3 | *.min.css 4 | 5 | # 其他类型文件 6 | *.js 7 | *.jpg 8 | *.woff 9 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "esbenp.prettier-vscode", 4 | "stylelint.vscode-stylelint", 5 | "vue.volar" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 2, 3 | "editor.defaultFormatter": "esbenp.prettier-vscode", 4 | "editor.codeActionsOnSave": { 5 | "source.fixAll.eslint": "explicit", 6 | "source.fixAll.stylelint": "explicit" 7 | }, 8 | "eslint.format.enable": true, 9 | "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "vue"], 10 | "[vue]": { 11 | "editor.formatOnSave": true, 12 | "editor.defaultFormatter": "esbenp.prettier-vscode", 13 | }, 14 | "[typescriptreact]": { 15 | "editor.formatOnSave": true, 16 | "editor.defaultFormatter": "esbenp.prettier-vscode" 17 | }, 18 | "[javascriptreact]": { 19 | "editor.formatOnSave": true, 20 | "editor.defaultFormatter": "esbenp.prettier-vscode" 21 | }, 22 | "[typescript]": { 23 | "editor.formatOnSave": true, 24 | "editor.defaultFormatter": "esbenp.prettier-vscode" 25 | }, 26 | "[javascript]": { 27 | "editor.formatOnSave": true, 28 | "editor.defaultFormatter": "esbenp.prettier-vscode" 29 | }, 30 | "[html]": { 31 | "editor.defaultFormatter": "esbenp.prettier-vscode" 32 | }, 33 | "[css]": { 34 | "editor.defaultFormatter": "esbenp.prettier-vscode" 35 | }, 36 | "[less]": { 37 | "editor.defaultFormatter": "esbenp.prettier-vscode" 38 | }, 39 | "[scss]": { 40 | "editor.defaultFormatter": "esbenp.prettier-vscode" 41 | }, 42 | "[markdown]": { 43 | "editor.defaultFormatter": "esbenp.prettier-vscode" 44 | }, 45 | "cSpell.words": ["tdesign", "tvision", "echarts", "nprogress", "commitlint", "stylelint", "pinia", "qrcode"], 46 | "stylelint.enable": true, 47 | "stylelint.snippet": ["css", "less", "postcss", "vue", "sass"], 48 | "stylelint.validate": ["css", "less", "postcss", "vue", "sass"] 49 | } 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 dianjie 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /build/vite/mock.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { normalizePath } from 'vite'; 3 | import { viteMockServe } from 'vite-plugin-mock'; 4 | 5 | function getDefaultPath() { 6 | return path.resolve(process.cwd(), `src/main.ts`); 7 | } 8 | 9 | export function createMock(command: string, mode: string) { 10 | let tempConfig = viteMockServe({ 11 | mockPath: 'mock', 12 | enable: mode === 'mock', 13 | logger: true, 14 | }); 15 | const defaultPath = getDefaultPath(); 16 | const defaultEnter = normalizePath(defaultPath); 17 | tempConfig = { 18 | ...tempConfig, 19 | async transform(code, id) { 20 | if (!id.endsWith(defaultEnter)) { 21 | return null; 22 | } 23 | // build && mock 24 | if (command === 'build' && mode === 'mock') { 25 | const injectCode = ` 26 | import { setupProdMockServer } from './mockProdServer'; 27 | setupProdMockServer(); 28 | `; 29 | return { 30 | map: null, 31 | code: `${code}\n${injectCode}`, 32 | }; 33 | } 34 | return null; 35 | }, 36 | }; 37 | return tempConfig; 38 | } 39 | -------------------------------------------------------------------------------- /build/vite/proxy.ts: -------------------------------------------------------------------------------- 1 | import type { ProxyOptions } from 'vite'; 2 | 3 | type ProxyItem = [string, string, boolean]; 4 | 5 | type ProxyList = ProxyItem[]; 6 | 7 | type ProxyTargetList = Record; 8 | 9 | const httpsRE = /^https:\/\//; 10 | 11 | /** 12 | * Generate proxy 13 | * @param list 14 | */ 15 | export function createProxy(list: ProxyList = []) { 16 | const ret: ProxyTargetList = {}; 17 | for (const [prefix, target, rewrite] of list) { 18 | const isHttps = httpsRE.test(target); 19 | 20 | // https://github.com/http-party/node-http-proxy#options 21 | ret[prefix] = { 22 | target, 23 | changeOrigin: true, 24 | ws: true, 25 | ...(rewrite ? { rewrite: (path) => path.replace(new RegExp(`^${prefix}`), '') } : {}), 26 | // https is require secure=false 27 | ...(isHttps ? { secure: false } : {}), 28 | }; 29 | } 30 | return ret; 31 | } 32 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | // commit-lint config 2 | export default { 3 | extends: ['@commitlint/config-conventional'], 4 | rules: { 5 | 'type-enum': [ 6 | 2, 7 | 'always', 8 | ['build', 'chore', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'style', 'test', 'types'], 9 | ], 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /docs/starter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dianjie/tdesign-console/d68b7b286ec455f7d6000525e77d258a8016527a/docs/starter.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | TDesign Vue Next Starter 8 | 9 | 10 |
11 | 12 | 13 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /mock/system/client.ts: -------------------------------------------------------------------------------- 1 | import type { MockMethod } from 'vite-plugin-mock'; 2 | 3 | const list = [ 4 | { 5 | id: '1123598811738675201', 6 | createUser: '1123598815738675201', 7 | createDept: '1123598813738675201', 8 | createTime: '2019-03-24 10:40:55', 9 | updateUser: '1123598815738675201', 10 | updateTime: '2019-03-24 10:40:59', 11 | status: 1, 12 | isDeleted: 0, 13 | clientId: 'sword', 14 | clientSecret: 'sword_secret', 15 | resourceIds: '', 16 | scope: 'all', 17 | authorizedGrantTypes: 'refresh_token,password,authorization_code,captcha,social', 18 | webServerRedirectUri: 'http://localhost:8888', 19 | authorities: '', 20 | accessTokenValidity: 3600, 21 | refreshTokenValidity: 604800, 22 | autoapprove: '', 23 | }, 24 | { 25 | id: '1123598811738675202', 26 | createUser: '1123598815738675201', 27 | createDept: '1123598813738675201', 28 | createTime: '2019-03-24 10:42:29', 29 | updateUser: '1123598815738675201', 30 | updateTime: '2019-03-24 10:42:32', 31 | status: 1, 32 | isDeleted: 0, 33 | clientId: 'saber', 34 | clientSecret: 'saber_secret', 35 | resourceIds: '', 36 | scope: 'all', 37 | authorizedGrantTypes: 'refresh_token,password,authorization_code,captcha,social', 38 | webServerRedirectUri: 'http://localhost:8080', 39 | authorities: '', 40 | accessTokenValidity: 3600, 41 | refreshTokenValidity: 604800, 42 | autoapprove: '', 43 | }, 44 | { 45 | id: '1123598811738675203', 46 | createUser: '1123598815738675201', 47 | createDept: '1123598813738675201', 48 | createTime: '2021-06-15 22:22:22', 49 | updateUser: '1123598815738675201', 50 | updateTime: '2021-06-15 22:22:22', 51 | status: 1, 52 | isDeleted: 0, 53 | clientId: 'rider', 54 | clientSecret: 'rider_secret', 55 | resourceIds: '', 56 | scope: 'all', 57 | authorizedGrantTypes: 'refresh_token,password,authorization_code,captcha,social', 58 | webServerRedirectUri: 'http://localhost:8080', 59 | authorities: '', 60 | accessTokenValidity: 3600, 61 | refreshTokenValidity: 604800, 62 | autoapprove: '', 63 | }, 64 | ]; 65 | 66 | export default [ 67 | { 68 | url: '/api/blade-system/client/list', 69 | method: 'get', 70 | response: () => { 71 | return { 72 | code: 200, 73 | success: true, 74 | data: { 75 | records: list, 76 | total: 6, 77 | size: 10, 78 | current: 1, 79 | orders: [], 80 | optimizeCountSql: true, 81 | searchCount: true, 82 | countId: '', 83 | maxLimit: -1, 84 | pages: 1, 85 | }, 86 | msg: '操作成功', 87 | }; 88 | }, 89 | }, 90 | { 91 | url: '/api/blade-system/client/detail', 92 | method: 'get', 93 | response: ({ query }) => { 94 | const { id } = query; 95 | return { 96 | code: 200, 97 | success: true, 98 | data: list.find((item) => item.id === id) || {}, 99 | msg: '操作成功', 100 | }; 101 | }, 102 | }, 103 | ] as MockMethod[]; 104 | -------------------------------------------------------------------------------- /mock/system/dictbiz.ts: -------------------------------------------------------------------------------- 1 | import type { MockMethod } from 'vite-plugin-mock'; 2 | 3 | const parentList = [ 4 | { 5 | id: '1204762018230317058', 6 | tenantId: '000000', 7 | parentId: '0', 8 | code: 'user', 9 | dictKey: '-1', 10 | dictValue: '用户类型', 11 | sort: 1, 12 | remark: '', 13 | isSealed: 0, 14 | isDeleted: 0, 15 | parentName: '顶级', 16 | hasChildren: false, 17 | }, 18 | ]; 19 | const childList = [ 20 | { 21 | id: '1204762253950201857', 22 | tenantId: '000000', 23 | parentId: '1204762018230317058', 24 | code: 'user', 25 | dictKey: '1', 26 | dictValue: '系统用户', 27 | sort: 1, 28 | remark: '', 29 | isSealed: 0, 30 | isDeleted: 0, 31 | parentName: '用户类型', 32 | hasChildren: false, 33 | }, 34 | { 35 | id: '1204762300687331329', 36 | tenantId: '000000', 37 | parentId: '1204762018230317058', 38 | code: 'user', 39 | dictKey: '2', 40 | dictValue: '网站用户', 41 | sort: 2, 42 | remark: '', 43 | isSealed: 0, 44 | isDeleted: 0, 45 | parentName: '用户类型', 46 | hasChildren: false, 47 | }, 48 | ]; 49 | 50 | const fullList = [...parentList, ...childList]; 51 | 52 | export default [ 53 | { 54 | url: '/api/blade-system/dict-biz/dictionary', 55 | method: 'get', 56 | response: ({ query }) => { 57 | const { code } = query; 58 | const dataConfig = { 59 | user: childList, 60 | }; 61 | return { 62 | code: 200, 63 | success: true, 64 | data: dataConfig[code] || [], 65 | msg: '操作成功', 66 | }; 67 | }, 68 | }, 69 | { 70 | url: '/api/blade-system/dict-biz/parent-list', 71 | method: 'get', 72 | response: () => { 73 | return { 74 | code: 200, 75 | success: true, 76 | data: { 77 | records: parentList, 78 | total: 1, 79 | size: 10, 80 | current: 1, 81 | orders: [], 82 | optimizeCountSql: true, 83 | searchCount: true, 84 | countId: '', 85 | maxLimit: -1, 86 | pages: 1, 87 | }, 88 | msg: '操作成功', 89 | }; 90 | }, 91 | }, 92 | { 93 | url: '/api/blade-system/dict-biz/child-list', 94 | method: 'get', 95 | response: () => { 96 | return { 97 | code: 200, 98 | success: true, 99 | data: childList, 100 | msg: '操作成功', 101 | }; 102 | }, 103 | }, 104 | { 105 | url: '/api/blade-system/dict-biz/detail', 106 | method: 'get', 107 | response: ({ query }) => { 108 | const { id } = query; 109 | return { 110 | code: 200, 111 | success: true, 112 | data: fullList.find((item) => item.id === id) || {}, 113 | msg: '操作成功', 114 | }; 115 | }, 116 | }, 117 | ] as MockMethod[]; 118 | -------------------------------------------------------------------------------- /mock/system/tenant.ts: -------------------------------------------------------------------------------- 1 | import type { MockMethod } from 'vite-plugin-mock'; 2 | 3 | const tenantList = [ 4 | { 5 | id: '1123598820738675201', 6 | createUser: '1123598821738675201', 7 | createDept: '1123598813738675201', 8 | createTime: '2019-01-01 00:00:39', 9 | updateUser: '1123598821738675201', 10 | updateTime: '2019-01-01 00:00:39', 11 | status: 1, 12 | isDeleted: 0, 13 | tenantId: '000000', 14 | tenantName: '管理组', 15 | domainUrl: 'http://saber.bladex.vip', 16 | backgroundUrl: 'https://saber.bladex.vip/img/bg/bg.jpg', 17 | linkman: 'admin', 18 | contactNumber: '666666', 19 | address: '管理组', 20 | accountNumber: 2333, 21 | expireTime: '2099-01-01 00:00:00', 22 | packageId: null, 23 | datasourceId: null, 24 | licenseKey: '', 25 | }, 26 | { 27 | id: '1226473230699630594', 28 | createUser: '1123598821738675201', 29 | createDept: '1123598813738675201', 30 | createTime: '2020-02-09 19:49:40', 31 | updateUser: '1123598821738675201', 32 | updateTime: '2020-02-09 19:50:18', 33 | status: 1, 34 | isDeleted: 0, 35 | tenantId: '763196', 36 | tenantName: '用户组', 37 | domainUrl: 'http://user.bladex.vip', 38 | backgroundUrl: '', 39 | linkman: 'user', 40 | contactNumber: '13888888888', 41 | address: '', 42 | accountNumber: 23333, 43 | expireTime: '2030-02-01 12:00:00', 44 | packageId: null, 45 | datasourceId: null, 46 | licenseKey: '', 47 | }, 48 | { 49 | id: '1226473265160032258', 50 | createUser: '1123598821738675201', 51 | createDept: '1123598813738675201', 52 | createTime: '2020-02-09 19:49:48', 53 | updateUser: '1123598821738675201', 54 | updateTime: '2020-02-09 19:50:04', 55 | status: 1, 56 | isDeleted: 0, 57 | tenantId: '648897', 58 | tenantName: '测试组', 59 | domainUrl: 'http://test.bladex.vip', 60 | backgroundUrl: '', 61 | linkman: 'test', 62 | contactNumber: '13888888888', 63 | address: '', 64 | accountNumber: -1, 65 | expireTime: '', 66 | packageId: null, 67 | datasourceId: null, 68 | licenseKey: '', 69 | }, 70 | ]; 71 | 72 | export default [ 73 | { 74 | url: '/api/blade-system/tenant/select', 75 | method: 'get', 76 | response: () => { 77 | return { 78 | code: 200, 79 | success: true, 80 | data: tenantList, 81 | msg: '操作成功', 82 | }; 83 | }, 84 | }, 85 | { 86 | url: '/api/blade-system/tenant/list', 87 | method: 'get', 88 | response: () => { 89 | return { 90 | code: 200, 91 | success: true, 92 | data: { 93 | records: tenantList, 94 | total: 6, 95 | size: 10, 96 | current: 1, 97 | orders: [], 98 | optimizeCountSql: true, 99 | searchCount: true, 100 | countId: '', 101 | maxLimit: -1, 102 | pages: 1, 103 | }, 104 | msg: '操作成功', 105 | }; 106 | }, 107 | }, 108 | { 109 | url: '/api/blade-system/tenant/detail', 110 | method: 'get', 111 | response: ({ query }) => { 112 | const { id } = query; 113 | return { 114 | code: 200, 115 | success: true, 116 | data: tenantList.find((item) => item.id === id) || {}, 117 | msg: '操作成功', 118 | }; 119 | }, 120 | }, 121 | ] as MockMethod[]; 122 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dianjie/tdesign-console/d68b7b286ec455f7d6000525e77d258a8016527a/public/favicon.ico -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 29 | 34 | -------------------------------------------------------------------------------- /src/api/authority/apiscope.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | enum Api { 4 | GetList = '/blade-system/api-scope/list', 5 | Remove = '/blade-system/api-scope/remove', 6 | GetDetail = '/blade-system/api-scope/detail', 7 | Submit = '/blade-system/api-scope/submit', 8 | } 9 | 10 | export const getList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 11 | return request.get( 12 | { 13 | url: Api.GetList, 14 | params: { 15 | ...params, 16 | current, 17 | size, 18 | }, 19 | }, 20 | { joinTime: false }, 21 | ); 22 | }; 23 | 24 | export const getDetail = (id: string) => { 25 | return request.get({ 26 | url: Api.GetDetail, 27 | params: { 28 | id, 29 | }, 30 | }); 31 | }; 32 | 33 | export const remove = (ids: string[]) => { 34 | return request.post( 35 | { url: Api.Remove, params: { ids } }, 36 | { 37 | joinParamsToUrl: true, 38 | errorMessageMode: 'message', 39 | }, 40 | ); 41 | }; 42 | 43 | export const submit = (data: Recordable) => { 44 | return request.post( 45 | { 46 | url: Api.Submit, 47 | data, 48 | }, 49 | { 50 | errorMessageMode: 'message', 51 | }, 52 | ); 53 | }; 54 | -------------------------------------------------------------------------------- /src/api/authority/datascope.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | enum Api { 4 | GetList = '/blade-system/data-scope/list', 5 | Remove = '/blade-system/data-scope/remove', 6 | GetDetail = '/blade-system/data-scope/detail', 7 | Submit = '/blade-system/data-scope/submit', 8 | } 9 | 10 | export const getList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 11 | return request.get( 12 | { 13 | url: Api.GetList, 14 | params: { 15 | ...params, 16 | current, 17 | size, 18 | }, 19 | }, 20 | { joinTime: false }, 21 | ); 22 | }; 23 | 24 | export const getDetail = (id: string) => { 25 | return request.get({ 26 | url: Api.GetDetail, 27 | params: { 28 | id, 29 | }, 30 | }); 31 | }; 32 | 33 | export const remove = (ids: string[]) => { 34 | return request.post( 35 | { url: Api.Remove, params: { ids } }, 36 | { 37 | joinParamsToUrl: true, 38 | errorMessageMode: 'message', 39 | }, 40 | ); 41 | }; 42 | 43 | export const submit = (data: Recordable) => { 44 | return request.post( 45 | { 46 | url: Api.Submit, 47 | data, 48 | }, 49 | { 50 | errorMessageMode: 'message', 51 | }, 52 | ); 53 | }; 54 | -------------------------------------------------------------------------------- /src/api/base/region.ts: -------------------------------------------------------------------------------- 1 | import type { UploadFileParams } from '@/types/axios'; 2 | import { request } from '@/utils/request'; 3 | 4 | enum Api { 5 | GetList = '/blade-system/region/list', 6 | GetLazyTree = '/blade-system/region/lazy-tree', 7 | Remove = '/blade-system/region/remove', 8 | GetDetail = '/blade-system/region/detail', 9 | Submit = '/blade-system/region/submit', 10 | ImportRegion = '/blade-system/region/import-region', 11 | ExportTemplate = '/blade-system/region/export-template', 12 | ExportRegion = '/blade-system/region/export-region', 13 | } 14 | 15 | export const getList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 16 | return request.get( 17 | { 18 | url: Api.GetList, 19 | params: { 20 | ...params, 21 | current, 22 | size, 23 | }, 24 | }, 25 | { 26 | joinTime: false, 27 | }, 28 | ); 29 | }; 30 | 31 | export const getLazyTree = (parentCode: StrOrNum, params?: Recordable) => { 32 | return request.get( 33 | { 34 | url: Api.GetLazyTree, 35 | params: { 36 | ...params, 37 | parentCode, 38 | }, 39 | }, 40 | { 41 | joinTime: false, 42 | }, 43 | ); 44 | }; 45 | 46 | export const getDetail = (code: string) => { 47 | return request.get({ 48 | url: Api.GetDetail, 49 | params: { 50 | code, 51 | }, 52 | }); 53 | }; 54 | 55 | export const remove = (id: string) => { 56 | return request.post( 57 | { url: Api.Remove, params: { id } }, 58 | { 59 | joinParamsToUrl: true, 60 | errorMessageMode: 'message', 61 | }, 62 | ); 63 | }; 64 | 65 | export const submit = (data: Recordable) => { 66 | return request.post( 67 | { 68 | url: Api.Submit, 69 | data, 70 | }, 71 | { 72 | errorMessageMode: 'message', 73 | }, 74 | ); 75 | }; 76 | 77 | export const importRegion = (isCovered: StrOrNum, params: UploadFileParams) => { 78 | return request.uploadFile( 79 | { 80 | url: Api.ImportRegion, 81 | params: { 82 | isCovered, 83 | }, 84 | timeout: 60 * 1000, 85 | }, 86 | params, 87 | ); 88 | }; 89 | 90 | export const exportTemplate = () => { 91 | return request.get( 92 | { 93 | url: Api.ExportTemplate, 94 | responseType: 'blob', 95 | }, 96 | { 97 | // 需要对返回数据进行处理 98 | isTransformResponse: false, 99 | }, 100 | ); 101 | }; 102 | 103 | export const exportRegion = () => { 104 | return request.get( 105 | { 106 | url: Api.ExportRegion, 107 | responseType: 'blob', 108 | timeout: 60 * 1000, 109 | }, 110 | { 111 | // 需要对返回数据进行处理 112 | joinTime: false, 113 | isTransformResponse: false, 114 | errorMessageMode: 'message', 115 | }, 116 | ); 117 | }; 118 | -------------------------------------------------------------------------------- /src/api/log/api.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | enum Api { 4 | GetList = '/blade-log/api/list', 5 | GetDetail = '/blade-log/api/detail', 6 | } 7 | 8 | export const getList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 9 | return request.get( 10 | { 11 | url: Api.GetList, 12 | params: { 13 | ...params, 14 | current, 15 | size, 16 | }, 17 | }, 18 | { 19 | joinTime: false, 20 | }, 21 | ); 22 | }; 23 | 24 | export const getDetail = (id: string) => { 25 | return request.get({ 26 | url: Api.GetDetail, 27 | params: { 28 | id, 29 | }, 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /src/api/log/error.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | enum Api { 4 | GetList = '/blade-log/error/list', 5 | GetDetail = '/blade-log/error/detail', 6 | } 7 | 8 | export const getList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 9 | return request.get( 10 | { 11 | url: Api.GetList, 12 | params: { 13 | ...params, 14 | current, 15 | size, 16 | }, 17 | }, 18 | { 19 | joinTime: false, 20 | }, 21 | ); 22 | }; 23 | 24 | export const getDetail = (id: string) => { 25 | return request.get({ 26 | url: Api.GetDetail, 27 | params: { 28 | id, 29 | }, 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /src/api/log/usual.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | enum Api { 4 | GetList = '/blade-log/usual/list', 5 | GetDetail = '/blade-log/usual/detail', 6 | } 7 | 8 | export const getList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 9 | return request.get( 10 | { 11 | url: Api.GetList, 12 | params: { 13 | ...params, 14 | current, 15 | size, 16 | }, 17 | }, 18 | { 19 | joinTime: false, 20 | }, 21 | ); 22 | }; 23 | 24 | export const getDetail = (id: string) => { 25 | return request.get({ 26 | url: Api.GetDetail, 27 | params: { 28 | id, 29 | }, 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /src/api/model/baseModel.ts: -------------------------------------------------------------------------------- 1 | export interface BasicSubmitResult { 2 | code: number; 3 | msg: string; 4 | data: any; 5 | success: boolean; 6 | } 7 | 8 | export interface BasicPageParams { 9 | current: number; 10 | size: number; 11 | } 12 | 13 | export type BasicDetailParams = { 14 | id: string; 15 | }; 16 | export interface BasicRemoveParams { 17 | ids: string | string[]; 18 | } 19 | 20 | export interface BasicFetchResult { 21 | data: T[]; 22 | total: number; 23 | } 24 | 25 | export interface BasicDataResult { 26 | data: BasicData; 27 | total: number; 28 | } 29 | 30 | export interface BasicData { 31 | records: T[]; 32 | total: number; 33 | } 34 | 35 | export interface BasicDetailResult { 36 | data: T; 37 | } 38 | 39 | export interface BasicPagination { 40 | pageSize: number; 41 | total: number; 42 | current: number; 43 | } 44 | -------------------------------------------------------------------------------- /src/api/model/detailModel.ts: -------------------------------------------------------------------------------- 1 | export interface PurchaseListResult { 2 | list: Array; 3 | } 4 | export interface PurchaseInfo { 5 | adminName: string; 6 | index: string; 7 | pdName: string; 8 | pdNum: string; 9 | pdType: string; 10 | purchaseNum: number; 11 | updateTime: Date; 12 | } 13 | 14 | export interface ProjectListResult { 15 | list: Array; 16 | } 17 | export interface ProjectInfo { 18 | adminName: string; 19 | adminPhone: string; 20 | index: number; 21 | name: string; 22 | updateTime: Date; 23 | } 24 | -------------------------------------------------------------------------------- /src/api/model/listModel.ts: -------------------------------------------------------------------------------- 1 | export interface ListResult { 2 | list: Array; 3 | } 4 | export interface ListModel { 5 | adminName: string; 6 | amount: string; 7 | contractType: number; 8 | index: number; 9 | name: string; 10 | no: string; 11 | paymentType: number; 12 | status: number; 13 | updateTime: Date; 14 | } 15 | 16 | export interface CardListResult { 17 | list: Array; 18 | } 19 | export interface CardList { 20 | banner: string; 21 | description: string; 22 | index: number; 23 | isSetup: boolean; 24 | name: string; 25 | type: number; 26 | } 27 | -------------------------------------------------------------------------------- /src/api/model/permissionModel.ts: -------------------------------------------------------------------------------- 1 | import type { defineComponent } from 'vue'; 2 | 3 | import type { RouteMeta } from '@/types/interface'; 4 | 5 | export interface MenuListResult { 6 | list: Array; 7 | } 8 | 9 | export type Component = 10 | | ReturnType 11 | | (() => Promise) 12 | | (() => Promise); 13 | 14 | export interface RouteItem { 15 | path: string; 16 | name: string; 17 | component?: Component | string; 18 | components?: Component; 19 | redirect?: string; 20 | meta: RouteMeta; 21 | children?: Array; 22 | } 23 | -------------------------------------------------------------------------------- /src/api/process/leave.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | enum Api { 4 | LeaveProcess = '/blade-desk/process/leave/start-process', 5 | LeaveDetail = '/blade-desk/process/leave/detail', 6 | } 7 | 8 | export const leaveProcess = (data: Recordable) => { 9 | return request.post( 10 | { 11 | url: Api.LeaveProcess, 12 | data, 13 | }, 14 | { 15 | errorMessageMode: 'message', 16 | }, 17 | ); 18 | }; 19 | export const leaveDetail = (businessId: string) => { 20 | return request.get({ 21 | url: Api.LeaveDetail, 22 | params: { 23 | businessId, 24 | }, 25 | }); 26 | }; 27 | -------------------------------------------------------------------------------- /src/api/process/process.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | enum Api { 4 | HistoryFlowList = '/blade-flow/process/history-flow-list', 5 | } 6 | 7 | export const historyFlowList = (processInstanceId: string) => { 8 | return request.get({ 9 | url: Api.HistoryFlowList, 10 | params: { 11 | processInstanceId, 12 | }, 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /src/api/resource/attach.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | enum Api { 4 | GetList = '/blade-resource/attach/list', 5 | Remove = '/blade-resource/attach/remove', 6 | GetDetail = '/blade-resource/attach/detail', 7 | Submit = '/blade-resource/attach/submit', 8 | } 9 | 10 | export const getList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 11 | return request.get( 12 | { 13 | url: Api.GetList, 14 | params: { 15 | ...params, 16 | current, 17 | size, 18 | }, 19 | }, 20 | { 21 | joinTime: false, 22 | }, 23 | ); 24 | }; 25 | 26 | export const getDetail = (id: string) => { 27 | return request.get({ 28 | url: Api.GetDetail, 29 | params: { 30 | id, 31 | }, 32 | }); 33 | }; 34 | 35 | export const remove = (ids: string[]) => { 36 | return request.post( 37 | { url: Api.Remove, params: { ids } }, 38 | { 39 | joinParamsToUrl: true, 40 | errorMessageMode: 'message', 41 | }, 42 | ); 43 | }; 44 | 45 | export const submit = (data: Recordable) => { 46 | return request.post({ 47 | url: Api.Submit, 48 | data, 49 | }); 50 | }; 51 | -------------------------------------------------------------------------------- /src/api/resource/model/ossModel.ts: -------------------------------------------------------------------------------- 1 | import type { BasicPageParams } from '@/api/model/baseModel'; 2 | 3 | export type DetailParams = { 4 | id?: string; 5 | }; 6 | 7 | export type ParamParams = { 8 | tenantId?: string; 9 | }; 10 | 11 | export type ParamPageParams = BasicPageParams & OssParams; 12 | 13 | export type OssParams = { 14 | category?: string; 15 | ossCode?: string; 16 | accessKey?: string; 17 | }; 18 | 19 | export type UploadParams = { 20 | code?: string; 21 | file: File; 22 | }; 23 | -------------------------------------------------------------------------------- /src/api/resource/oss.ts: -------------------------------------------------------------------------------- 1 | import type { UploadFileParams } from '@/types/axios'; 2 | import { request } from '@/utils/request'; 3 | 4 | import type { UploadApiResult } from '../system/model/uploadModel'; 5 | import type { OssParams, UploadParams } from './model/ossModel'; 6 | 7 | enum Api { 8 | OssList = '/blade-resource/oss/list', 9 | SubmitOss = '/blade-resource/oss/submit', 10 | OssDetail = '/blade-resource/oss/detail', 11 | OssRemove = '/blade-resource/oss/remove', 12 | OssEnable = '/blade-resource/oss/enable', 13 | OssUpload = '/blade-resource/oss/endpoint/put-file', 14 | // 附件上传,好像和上面的一样的吧 15 | OssAttachUpload = '/blade-resource/oss/endpoint/put-file-attach', 16 | } 17 | 18 | // oss列表 19 | export const getOssList = (current: StrOrNum, size: StrOrNum, params: OssParams) => { 20 | return request.get( 21 | { 22 | url: Api.OssList, 23 | params: { 24 | ...params, 25 | current, 26 | size, 27 | }, 28 | }, 29 | { joinTime: false }, 30 | ); 31 | }; 32 | 33 | // oss提交 34 | export const submitOss = (data: Recordable) => { 35 | return request.post({ url: Api.SubmitOss, data }); 36 | }; 37 | 38 | // oss上传 39 | export const uploadOss = (params: UploadParams) => { 40 | return request.uploadFile( 41 | { 42 | url: Api.OssUpload, 43 | params: { code: params.code }, 44 | timeout: 60 * 1000, 45 | }, 46 | params, 47 | ); 48 | }; 49 | 50 | // oss上传 51 | export const uploadOssDefult = (params: UploadFileParams) => { 52 | return request.uploadFile( 53 | { 54 | url: Api.OssUpload, 55 | timeout: 60 * 1000, 56 | }, 57 | params, 58 | ); 59 | }; 60 | 61 | // oss启用操作 62 | export const enableOss = (id: StrOrNum) => 63 | request.post({ url: Api.OssEnable, params: { id } }, { joinParamsToUrl: true }); 64 | 65 | // oss详情 66 | export const getOssDetail = (id: StrOrNum) => request.get({ url: Api.OssDetail, params: { id } }); 67 | 68 | // oss删除 69 | export const removeOss = (ids: string | string[]) => 70 | request.post({ url: Api.OssRemove, params: { ids } }, { joinParamsToUrl: true }); 71 | 72 | export const uploadAttachOss = (params: UploadParams) => { 73 | return request.uploadFile( 74 | { 75 | url: Api.OssAttachUpload, 76 | timeout: 60 * 1000, 77 | }, 78 | params, 79 | ); 80 | }; 81 | -------------------------------------------------------------------------------- /src/api/resource/sms.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | enum Api { 4 | GetList = '/blade-resource/sms/list', 5 | Remove = '/blade-resource/sms/remove', 6 | GetDetail = '/blade-resource/sms/detail', 7 | Submit = '/blade-resource/sms/submit', 8 | Enable = '/blade-resource/sms/enable', 9 | SendMessage = '/blade-resource/sms/endpoint/send-message', 10 | } 11 | 12 | export const getList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 13 | return request.get( 14 | { 15 | url: Api.GetList, 16 | params: { 17 | ...params, 18 | current, 19 | size, 20 | }, 21 | }, 22 | { 23 | joinTime: false, 24 | }, 25 | ); 26 | }; 27 | 28 | export const getDetail = (id: string) => { 29 | return request.get({ 30 | url: Api.GetDetail, 31 | params: { 32 | id, 33 | }, 34 | }); 35 | }; 36 | 37 | export const remove = (ids: string[]) => { 38 | return request.post( 39 | { url: Api.Remove, params: { ids } }, 40 | { 41 | joinParamsToUrl: true, 42 | errorMessageMode: 'message', 43 | }, 44 | ); 45 | }; 46 | 47 | export const submit = (data: Recordable) => { 48 | return request.post( 49 | { 50 | url: Api.Submit, 51 | data, 52 | }, 53 | { 54 | errorMessageMode: 'message', 55 | }, 56 | ); 57 | }; 58 | 59 | export const enable = (id: StrOrNum) => { 60 | return request.post({ url: Api.Enable, params: { id } }, { joinParamsToUrl: true }); 61 | }; 62 | 63 | export const sendMessage = (params: { code: string; phones: string; params: string }) => { 64 | return request.post( 65 | { url: Api.SendMessage, params }, 66 | { 67 | joinParamsToUrl: true, 68 | errorMessageMode: 'message', 69 | }, 70 | ); 71 | }; 72 | -------------------------------------------------------------------------------- /src/api/system/client.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | enum Api { 4 | GetList = '/blade-system/client/list', 5 | Remove = '/blade-system/client/remove', 6 | GetDetail = '/blade-system/client/detail', 7 | Submit = '/blade-system/client/submit', 8 | } 9 | 10 | export const getList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 11 | return request.get({ 12 | url: Api.GetList, 13 | params: { 14 | ...params, 15 | current, 16 | size, 17 | }, 18 | }); 19 | }; 20 | 21 | export const getDetail = (id: string) => { 22 | return request.get({ 23 | url: Api.GetDetail, 24 | params: { 25 | id, 26 | }, 27 | }); 28 | }; 29 | 30 | export const remove = (ids: string[]) => { 31 | return request.post( 32 | { url: Api.Remove, params: { ids } }, 33 | { 34 | joinParamsToUrl: true, 35 | errorMessageMode: 'message', 36 | }, 37 | ); 38 | }; 39 | 40 | export const submit = (data: Recordable) => { 41 | return request.post({ 42 | url: Api.Submit, 43 | data, 44 | }); 45 | }; 46 | -------------------------------------------------------------------------------- /src/api/system/dept.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | import type { LazyListParams } from './model/deptModel'; 4 | 5 | enum Api { 6 | GetLazyList = '/blade-system/dept/lazy-list', 7 | Remove = '/blade-system/dept/remove', 8 | Submit = '/blade-system/dept/submit', 9 | GetDetail = '/blade-system/dept/detail', 10 | GetTree = '/blade-system/dept/tree', 11 | GetLazyTree = '/blade-system/dept/lazy-tree', 12 | } 13 | 14 | export function getLazyList(params: LazyListParams) { 15 | return request.get( 16 | { url: Api.GetLazyList, params }, 17 | { 18 | clearEmptyParam: false, 19 | }, 20 | ); 21 | } 22 | 23 | export const removeDepts = (ids: string[]) => { 24 | return request.post( 25 | { url: Api.Remove, params: { ids } }, 26 | { 27 | joinParamsToUrl: true, 28 | errorMessageMode: 'message', 29 | }, 30 | ); 31 | }; 32 | 33 | export const submitDept = (data: Recordable) => { 34 | return request.post( 35 | { url: Api.Submit, data }, 36 | { 37 | errorMessageMode: 'message', 38 | }, 39 | ); 40 | }; 41 | 42 | export const getDeptDetail = (id: string) => { 43 | return request.get({ url: Api.GetDetail, params: { id } }); 44 | }; 45 | export const getDeptTree = (tenantId?: string) => { 46 | return request.get({ url: Api.GetTree, params: { tenantId } }); 47 | }; 48 | export const getDeptLazyTree = (params: any) => { 49 | return request.get( 50 | { url: Api.GetLazyTree, params }, 51 | { 52 | clearEmptyParam: false, 53 | joinTime: false, 54 | }, 55 | ); 56 | }; 57 | -------------------------------------------------------------------------------- /src/api/system/dict.ts: -------------------------------------------------------------------------------- 1 | // 系统字典 2 | import { request } from '@/utils/request'; 3 | 4 | enum Api { 5 | GetDict = '/blade-system/dict/dictionary', 6 | GetList = '/blade-system/dict/parent-list', 7 | GetChildList = '/blade-system/dict/child-list', 8 | Remove = '/blade-system/dict/remove', 9 | GetDetail = '/blade-system/dict/detail', 10 | Submit = '/blade-system/dict/submit', 11 | } 12 | 13 | export function getDictData(code: string) { 14 | return request.get({ url: Api.GetDict, params: { code } }); 15 | } 16 | 17 | export const getList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 18 | return request.get( 19 | { 20 | url: Api.GetList, 21 | params: { 22 | ...params, 23 | current, 24 | size, 25 | }, 26 | }, 27 | { 28 | joinTime: false, 29 | }, 30 | ); 31 | }; 32 | 33 | export const getChildList = (params: Recordable) => { 34 | return request.get( 35 | { 36 | url: Api.GetChildList, 37 | params, 38 | }, 39 | { 40 | joinTime: false, 41 | }, 42 | ); 43 | }; 44 | 45 | export const getDetail = (id: string) => { 46 | return request.get({ 47 | url: Api.GetDetail, 48 | params: { 49 | id, 50 | }, 51 | }); 52 | }; 53 | 54 | export const remove = (ids: string[]) => { 55 | return request.post( 56 | { url: Api.Remove, params: { ids } }, 57 | { 58 | joinParamsToUrl: true, 59 | errorMessageMode: 'message', 60 | }, 61 | ); 62 | }; 63 | 64 | export const submit = (data: Recordable) => { 65 | return request.post( 66 | { 67 | url: Api.Submit, 68 | data, 69 | }, 70 | { 71 | errorMessageMode: 'message', 72 | }, 73 | ); 74 | }; 75 | -------------------------------------------------------------------------------- /src/api/system/dictbiz.ts: -------------------------------------------------------------------------------- 1 | // 业务字典 2 | import { request } from '@/utils/request'; 3 | 4 | enum Api { 5 | GetDict = '/blade-system/dict-biz/dictionary', 6 | GetList = '/blade-system/dict-biz/parent-list', 7 | GetChildList = '/blade-system/dict-biz/child-list', 8 | Remove = '/blade-system/dict-biz/remove', 9 | GetDetail = '/blade-system/dict-biz/detail', 10 | Submit = '/blade-system/dict-biz/submit', 11 | } 12 | 13 | export function getDictData(code: string) { 14 | return request.get({ url: Api.GetDict, params: { code } }); 15 | } 16 | 17 | export const getList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 18 | return request.get( 19 | { 20 | url: Api.GetList, 21 | params: { 22 | ...params, 23 | current, 24 | size, 25 | }, 26 | }, 27 | { 28 | joinTime: false, 29 | }, 30 | ); 31 | }; 32 | 33 | export const getChildList = (params: Recordable) => { 34 | return request.get( 35 | { 36 | url: Api.GetChildList, 37 | params, 38 | }, 39 | { 40 | joinTime: false, 41 | }, 42 | ); 43 | }; 44 | 45 | export const getDetail = (id: string) => { 46 | return request.get({ 47 | url: Api.GetDetail, 48 | params: { 49 | id, 50 | }, 51 | }); 52 | }; 53 | 54 | export const remove = (ids: string[]) => { 55 | return request.post( 56 | { url: Api.Remove, params: { ids } }, 57 | { 58 | joinParamsToUrl: true, 59 | errorMessageMode: 'message', 60 | }, 61 | ); 62 | }; 63 | 64 | export const submit = (data: Recordable) => { 65 | return request.post( 66 | { 67 | url: Api.Submit, 68 | data, 69 | }, 70 | { 71 | errorMessageMode: 'message', 72 | }, 73 | ); 74 | }; 75 | -------------------------------------------------------------------------------- /src/api/system/menu.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | import type { GetButtonsModel, getMenuListResultModel, LazyListParams } from './model/menuModel'; 4 | 5 | export enum Api { 6 | GetMenuList = '/blade-system/menu/routes', 7 | GetButtons = '/blade-system/menu/buttons', 8 | GetLazyList = '/blade-system/menu/lazy-list', 9 | GetLazyMenuList = '/blade-system/menu/lazy-menu-list', 10 | Remove = '/blade-system/menu/remove', 11 | Tree = '/blade-system/menu/tree', 12 | GetDetail = '/blade-system/menu/detail', 13 | Submit = '/blade-system/menu/submit', 14 | } 15 | 16 | /** 17 | * @description: Get user menu based on id 18 | */ 19 | 20 | export const getMenuList = () => { 21 | return request.get({ url: Api.GetMenuList }); 22 | }; 23 | 24 | /** 25 | * @description: getButtons 26 | */ 27 | export function getButtons() { 28 | return request.get({ url: Api.GetButtons }); 29 | } 30 | 31 | export function getLazyList(params: LazyListParams) { 32 | return request.get({ url: Api.GetLazyList, params }); 33 | } 34 | 35 | export function getLazyMenuList(params: LazyListParams) { 36 | return request.get({ url: Api.GetLazyMenuList, params }); 37 | } 38 | 39 | export function removeByIds(ids: string[]) { 40 | return request.post( 41 | { url: Api.Remove, params: { ids } }, 42 | { 43 | joinParamsToUrl: true, 44 | errorMessageMode: 'message', 45 | }, 46 | ); 47 | } 48 | 49 | export function getTreeMenu() { 50 | return request.get({ url: Api.Tree }); 51 | } 52 | 53 | export function getMenuDetail(id: string) { 54 | return request.get({ url: Api.GetDetail, params: { id } }); 55 | } 56 | 57 | export function submitMenu(data: Recordable) { 58 | return request.post( 59 | { url: Api.Submit, data }, 60 | { 61 | errorMessageMode: 'message', 62 | }, 63 | ); 64 | } 65 | -------------------------------------------------------------------------------- /src/api/system/model/deptModel.ts: -------------------------------------------------------------------------------- 1 | export interface LazyListParams { 2 | deptName?: string; 3 | fullName?: string; 4 | parentId?: string | number; 5 | tenantId?: string | number; 6 | } 7 | -------------------------------------------------------------------------------- /src/api/system/model/menuModel.ts: -------------------------------------------------------------------------------- 1 | import type { RouteMeta } from 'vue-router'; 2 | 3 | export interface RouteItem { 4 | id: string; 5 | path: string; 6 | component: any; 7 | meta: RouteMeta; 8 | code: string; 9 | name: string; 10 | parentId: string; 11 | // 图标 12 | source: string; 13 | // alias?: string | string[]; 14 | redirect?: string; 15 | hasChildren: boolean; 16 | caseSensitive?: boolean; 17 | children?: RouteItem[]; 18 | } 19 | 20 | /** 21 | * @description: Get menu return value 22 | */ 23 | export type getMenuListResultModel = RouteItem[]; 24 | 25 | /** 26 | * 获取系统按钮权限 27 | */ 28 | export interface ButtonItem { 29 | id: string | number; 30 | code: string; 31 | hasChildren: boolean; 32 | children: ButtonItem[]; 33 | } 34 | 35 | export type GetButtonsModel = ButtonItem[]; 36 | 37 | export interface LazyListParams { 38 | code: string; 39 | name: string; 40 | parentId?: string | number; 41 | } 42 | -------------------------------------------------------------------------------- /src/api/system/model/uploadModel.ts: -------------------------------------------------------------------------------- 1 | export interface UploadApiResult { 2 | success?: boolean; 3 | link: string; 4 | domain: string; 5 | name: string; 6 | originalName: string; 7 | attachId: string; 8 | } 9 | -------------------------------------------------------------------------------- /src/api/system/model/userModel.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description: 登录接口参数 3 | */ 4 | export interface LoginParams { 5 | tenantId?: string; 6 | username?: string; 7 | password?: string; 8 | grant_type?: string; 9 | scope?: string; 10 | type?: string; 11 | key?: string; 12 | code?: string; 13 | source?: string; 14 | state?: string; 15 | } 16 | 17 | /** 18 | * @description: 登录接口返回值 19 | */ 20 | export interface LoginResultModel { 21 | access_token: string; 22 | user_id: string; 23 | avatar: string; 24 | dept_id: string; 25 | nick_name: string; 26 | post_id: string; 27 | refresh_token: string; 28 | expires_in: number; 29 | tenant_id: string; 30 | token_type: string; 31 | role_id: string; 32 | role_name: string; 33 | error_code?: number; 34 | error_description?: string; 35 | } 36 | 37 | export interface RefreshTokenParams { 38 | tenantId: string; 39 | refresh_token: string; 40 | } 41 | -------------------------------------------------------------------------------- /src/api/system/param.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | enum Api { 4 | GetList = '/blade-system/param/list', 5 | Remove = '/blade-system/param/remove', 6 | GetDetail = '/blade-system/param/detail', 7 | Submit = '/blade-system/param/submit', 8 | } 9 | 10 | export const getList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 11 | return request.get( 12 | { 13 | url: Api.GetList, 14 | params: { 15 | ...params, 16 | current, 17 | size, 18 | }, 19 | }, 20 | { 21 | joinTime: false, 22 | }, 23 | ); 24 | }; 25 | 26 | export const getDetail = (id: string) => { 27 | return request.get({ 28 | url: Api.GetDetail, 29 | params: { 30 | id, 31 | }, 32 | }); 33 | }; 34 | 35 | export const remove = (ids: string[]) => { 36 | return request.post( 37 | { url: Api.Remove, params: { ids } }, 38 | { 39 | joinParamsToUrl: true, 40 | errorMessageMode: 'message', 41 | }, 42 | ); 43 | }; 44 | 45 | export const submit = (data: Recordable) => { 46 | return request.post({ 47 | url: Api.Submit, 48 | data, 49 | }); 50 | }; 51 | -------------------------------------------------------------------------------- /src/api/system/post.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | enum Api { 4 | GetList = '/blade-system/post/list', 5 | Remove = '/blade-system/post/remove', 6 | GetDetail = '/blade-system/post/detail', 7 | Submit = '/blade-system/post/submit', 8 | GetPostList = '/blade-system/post/select', 9 | } 10 | 11 | export const getList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 12 | return request.get( 13 | { 14 | url: Api.GetList, 15 | params: { 16 | ...params, 17 | current, 18 | size, 19 | }, 20 | }, 21 | { joinTime: false }, 22 | ); 23 | }; 24 | 25 | export const getDetail = (id: string) => { 26 | return request.get({ 27 | url: Api.GetDetail, 28 | params: { 29 | id, 30 | }, 31 | }); 32 | }; 33 | 34 | export const remove = (ids: string[]) => { 35 | return request.post( 36 | { url: Api.Remove, params: { ids } }, 37 | { 38 | joinParamsToUrl: true, 39 | errorMessageMode: 'message', 40 | }, 41 | ); 42 | }; 43 | 44 | export const submit = (data: Recordable) => { 45 | return request.post({ 46 | url: Api.Submit, 47 | data, 48 | }); 49 | }; 50 | 51 | export const getPostList = (tenantId?: string) => { 52 | return request.get({ url: Api.GetPostList, params: { tenantId } }); 53 | }; 54 | -------------------------------------------------------------------------------- /src/api/system/role.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | enum Api { 4 | GetList = '/blade-system/role/list', 5 | Remove = '/blade-system/role/remove', 6 | Submit = '/blade-system/role/submit', 7 | GetDetail = '/blade-system/role/detail', 8 | GrantTree = '/blade-system/menu/grant-tree', 9 | Grant = '/blade-system/role/grant', 10 | getRole = '/blade-system/menu/role-tree-keys', 11 | GetRoleTree = '/blade-system/role/tree', 12 | GetRoleTreeById = '/blade-system/role/tree-by-id', 13 | } 14 | 15 | export const getList = (params: { roleAlias: string; roleName: string; tenantId: string }) => { 16 | return request.get( 17 | { 18 | url: Api.GetList, 19 | params: { 20 | ...params, 21 | }, 22 | }, 23 | { 24 | joinTime: false, 25 | }, 26 | ); 27 | }; 28 | 29 | export const remove = (ids: string[]) => { 30 | return request.post( 31 | { url: Api.Remove, params: { ids } }, 32 | { 33 | joinParamsToUrl: true, 34 | errorMessageMode: 'message', 35 | }, 36 | ); 37 | }; 38 | 39 | export const submit = (data: Recordable) => { 40 | return request.post( 41 | { url: Api.Submit, data }, 42 | { 43 | errorMessageMode: 'message', 44 | }, 45 | ); 46 | }; 47 | 48 | export const getDetail = (id: string) => { 49 | return request.get({ url: Api.GetDetail, params: { id } }); 50 | }; 51 | 52 | export const getRoleTree = (tenantId?: string) => { 53 | return request.get({ url: Api.GetRoleTree, params: { tenantId } }); 54 | }; 55 | 56 | export const getRole = (roleIds: string | string[]) => { 57 | return request.get( 58 | { url: Api.getRole, params: { roleIds } }, 59 | { 60 | clearEmptyParam: false, 61 | joinTime: false, 62 | }, 63 | ); 64 | }; 65 | 66 | export const getRoleTreeById = (roleId: string) => { 67 | return request.get({ url: Api.GetRoleTreeById, params: { roleId } }); 68 | }; 69 | 70 | export const grant = (roleIds: string[], menuIds: string[], dataScopeIds: string[], apiScopeIds: string[]) => { 71 | return request.post( 72 | { 73 | url: Api.Grant, 74 | data: { 75 | roleIds, 76 | menuIds, 77 | dataScopeIds, 78 | apiScopeIds, 79 | }, 80 | }, 81 | { 82 | errorMessageMode: 'message', 83 | }, 84 | ); 85 | }; 86 | 87 | export const grantTree = () => { 88 | return request.get({ url: Api.GrantTree }); 89 | }; 90 | -------------------------------------------------------------------------------- /src/api/system/tenant.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | enum Api { 4 | GetSelectList = '/blade-system/tenant/select', 5 | GetList = '/blade-system/tenant/list', 6 | Remove = '/blade-system/tenant/remove', 7 | GetDetail = '/blade-system/tenant/detail', 8 | Submit = '/blade-system/tenant/submit', 9 | Setting = '/blade-system/tenant/setting', 10 | Datasource = '/blade-system/tenant/datasource', 11 | Info = '/blade-system/tenant/info', 12 | PackageInfo = '/blade-system/tenant/package-detail', 13 | PackageSetting = '/blade-system/tenant/package-setting', 14 | DatasourceSelect = '/blade-develop/datasource/select', 15 | } 16 | 17 | export function getTenantSelectList() { 18 | return request.get({ url: Api.GetSelectList }); 19 | } 20 | 21 | export const getList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 22 | return request.get( 23 | { 24 | url: Api.GetList, 25 | params: { 26 | ...params, 27 | current, 28 | size, 29 | }, 30 | }, 31 | { 32 | joinTime: false, 33 | }, 34 | ); 35 | }; 36 | 37 | export const getDetail = (id: string) => { 38 | return request.get({ 39 | url: Api.GetDetail, 40 | params: { 41 | id, 42 | }, 43 | }); 44 | }; 45 | 46 | export const remove = (ids: string[]) => { 47 | return request.post( 48 | { url: Api.Remove, params: { ids } }, 49 | { 50 | joinParamsToUrl: true, 51 | errorMessageMode: 'message', 52 | }, 53 | ); 54 | }; 55 | 56 | export const submit = (data: Recordable) => { 57 | return request.post({ 58 | url: Api.Submit, 59 | data, 60 | }); 61 | }; 62 | 63 | export const setting = (params: { ids: string | string[]; accountNumber: StrOrNum; expireTime: string }) => { 64 | return request.post( 65 | { 66 | url: Api.Setting, 67 | params, 68 | }, 69 | { 70 | joinParamsToUrl: true, 71 | clearEmptyParam: false, 72 | errorMessageMode: 'message', 73 | }, 74 | ); 75 | }; 76 | 77 | export const datasource = (tenantId: string, datasourceId: string) => { 78 | return request.post( 79 | { 80 | url: Api.Datasource, 81 | params: { tenantId, datasourceId }, 82 | }, 83 | { 84 | joinParamsToUrl: true, 85 | clearEmptyParam: false, 86 | errorMessageMode: 'message', 87 | }, 88 | ); 89 | }; 90 | 91 | export const info = (domain: string) => { 92 | return request.get({ 93 | url: Api.Info, 94 | params: { 95 | domain, 96 | }, 97 | }); 98 | }; 99 | 100 | export const packageInfo = (tenantId: string) => { 101 | return request.get({ 102 | url: Api.PackageInfo, 103 | params: { 104 | tenantId, 105 | }, 106 | }); 107 | }; 108 | 109 | export const packageSetting = (tenantId: string, packageId: string) => { 110 | return request.post( 111 | { 112 | url: Api.PackageSetting, 113 | params: { 114 | tenantId, 115 | packageId, 116 | }, 117 | }, 118 | { 119 | joinParamsToUrl: true, 120 | clearEmptyParam: false, 121 | errorMessageMode: 'message', 122 | }, 123 | ); 124 | }; 125 | 126 | export const datasourceSelect = () => { 127 | return request.get({ 128 | url: Api.DatasourceSelect, 129 | }); 130 | }; 131 | -------------------------------------------------------------------------------- /src/api/system/tenantPackage.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | enum Api { 4 | GetList = '/blade-system/tenant-package/list', 5 | Remove = '/blade-system/tenant-package/remove', 6 | GetDetail = '/blade-system/tenant-package/detail', 7 | Submit = '/blade-system/tenant-package/submit', 8 | Select = '/blade-system/tenant-package/select', 9 | } 10 | 11 | export const getList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 12 | return request.get({ 13 | url: Api.GetList, 14 | params: { 15 | ...params, 16 | current, 17 | size, 18 | }, 19 | }); 20 | }; 21 | 22 | export const getDetail = (id: string) => { 23 | return request.get({ 24 | url: Api.GetDetail, 25 | params: { 26 | id, 27 | }, 28 | }); 29 | }; 30 | 31 | export const remove = (ids: string[]) => { 32 | return request.post( 33 | { url: Api.Remove, params: { ids } }, 34 | { 35 | joinParamsToUrl: true, 36 | errorMessageMode: 'message', 37 | }, 38 | ); 39 | }; 40 | 41 | export const submit = (data: Recordable) => { 42 | return request.post({ 43 | url: Api.Submit, 44 | data, 45 | }); 46 | }; 47 | 48 | export const getSelect = () => { 49 | return request.get({ 50 | url: Api.Select, 51 | }); 52 | }; 53 | -------------------------------------------------------------------------------- /src/api/system/topmenu.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | enum Api { 4 | GetList = '/blade-system/topmenu/list', 5 | Remove = '/blade-system/topmenu/remove', 6 | GetDetail = '/blade-system/topmenu/detail', 7 | Submit = '/blade-system/topmenu/submit', 8 | GrantTree = 'blade-system/menu/grant-top-tree', 9 | GetTopTree = 'blade-system/menu/top-tree-keys', 10 | Grant = 'blade-system/topmenu/grant', 11 | } 12 | 13 | export const getList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 14 | return request.get( 15 | { 16 | url: Api.GetList, 17 | params: { 18 | ...params, 19 | current, 20 | size, 21 | }, 22 | }, 23 | { 24 | joinTime: false, 25 | }, 26 | ); 27 | }; 28 | 29 | export const getDetail = (id: string) => { 30 | return request.get({ 31 | url: Api.GetDetail, 32 | params: { 33 | id, 34 | }, 35 | }); 36 | }; 37 | 38 | export const remove = (ids: string[]) => { 39 | return request.post( 40 | { url: Api.Remove, params: { ids } }, 41 | { 42 | joinParamsToUrl: true, 43 | errorMessageMode: 'message', 44 | }, 45 | ); 46 | }; 47 | 48 | export const submit = (data: Recordable) => { 49 | return request.post({ 50 | url: Api.Submit, 51 | data, 52 | }); 53 | }; 54 | 55 | export const grantTree = () => { 56 | return request.get({ 57 | url: Api.GrantTree, 58 | }); 59 | }; 60 | 61 | export const getTopTree = (topMenuIds: string) => { 62 | return request.get({ 63 | url: Api.GetTopTree, 64 | params: { 65 | topMenuIds, 66 | }, 67 | }); 68 | }; 69 | 70 | export const grant = (topMenuIds: string[], menuIds: string[]) => { 71 | return request.post({ 72 | url: Api.Grant, 73 | data: { 74 | topMenuIds, 75 | menuIds, 76 | }, 77 | }); 78 | }; 79 | -------------------------------------------------------------------------------- /src/api/tool/datasource.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | enum Api { 4 | GetList = '/blade-develop/datasource/list', 5 | Remove = '/blade-develop/datasource/remove', 6 | GetDetail = '/blade-develop/datasource/detail', 7 | Submit = '/blade-develop/datasource/submit', 8 | } 9 | 10 | export const getList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 11 | return request.get( 12 | { 13 | url: Api.GetList, 14 | params: { 15 | ...params, 16 | current, 17 | size, 18 | }, 19 | }, 20 | { 21 | joinTime: false, 22 | }, 23 | ); 24 | }; 25 | 26 | export const getDetail = (id: string) => { 27 | return request.get({ 28 | url: Api.GetDetail, 29 | params: { 30 | id, 31 | }, 32 | }); 33 | }; 34 | 35 | export const remove = (ids: string[]) => { 36 | return request.post( 37 | { url: Api.Remove, params: { ids } }, 38 | { 39 | joinParamsToUrl: true, 40 | errorMessageMode: 'message', 41 | }, 42 | ); 43 | }; 44 | 45 | export const submit = (data: Recordable) => { 46 | return request.post( 47 | { 48 | url: Api.Submit, 49 | data, 50 | }, 51 | { 52 | errorMessageMode: 'message', 53 | }, 54 | ); 55 | }; 56 | -------------------------------------------------------------------------------- /src/api/work/work.ts: -------------------------------------------------------------------------------- 1 | import { request } from '@/utils/request'; 2 | 3 | enum Api { 4 | StartList = '/blade-flow/work/start-list', 5 | ClaimList = '/blade-flow/work/claim-list', 6 | TodoList = '/blade-flow/work/todo-list', 7 | SendList = '/blade-flow/work/send-list', 8 | DoneList = '/blade-flow/work/done-list', 9 | ClaimTask = '/blade-flow/work/claim-task', 10 | CompleteTask = '/blade-flow/work/complete-task', 11 | } 12 | 13 | export const startList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 14 | return request.get( 15 | { 16 | url: Api.StartList, 17 | params: { 18 | ...params, 19 | current, 20 | size, 21 | }, 22 | }, 23 | { 24 | joinTime: false, 25 | }, 26 | ); 27 | }; 28 | 29 | export const claimList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 30 | return request.get( 31 | { 32 | url: Api.ClaimList, 33 | params: { 34 | ...params, 35 | current, 36 | size, 37 | }, 38 | }, 39 | { 40 | joinTime: false, 41 | }, 42 | ); 43 | }; 44 | 45 | export const todoList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 46 | return request.get( 47 | { 48 | url: Api.TodoList, 49 | params: { 50 | ...params, 51 | current, 52 | size, 53 | }, 54 | }, 55 | { 56 | joinTime: false, 57 | }, 58 | ); 59 | }; 60 | 61 | export const sendList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 62 | return request.get( 63 | { 64 | url: Api.SendList, 65 | params: { 66 | ...params, 67 | current, 68 | size, 69 | }, 70 | }, 71 | { 72 | joinTime: false, 73 | }, 74 | ); 75 | }; 76 | 77 | export const doneList = (current: StrOrNum, size: StrOrNum, params: Recordable) => { 78 | return request.get( 79 | { 80 | url: Api.DoneList, 81 | params: { 82 | ...params, 83 | current, 84 | size, 85 | }, 86 | }, 87 | { 88 | joinTime: false, 89 | }, 90 | ); 91 | }; 92 | 93 | export const claimTask = (taskId: string) => { 94 | return request.post( 95 | { url: Api.ClaimTask, params: { taskId } }, 96 | { 97 | joinParamsToUrl: true, 98 | errorMessageMode: 'message', 99 | }, 100 | ); 101 | }; 102 | 103 | export const completeTask = (data: Recordable) => { 104 | return request.post( 105 | { 106 | url: Api.CompleteTask, 107 | data, 108 | }, 109 | { 110 | errorMessageMode: 'message', 111 | }, 112 | ); 113 | }; 114 | -------------------------------------------------------------------------------- /src/assets/assets-empty.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/assets/assets-layout-mix.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/assets/assets-layout-side.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/assets/assets-layout-top.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/assets/assets-login-bg-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dianjie/tdesign-console/d68b7b286ec455f7d6000525e77d258a8016527a/src/assets/assets-login-bg-black.png -------------------------------------------------------------------------------- /src/assets/assets-login-bg-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dianjie/tdesign-console/d68b7b286ec455f7d6000525e77d258a8016527a/src/assets/assets-login-bg-white.png -------------------------------------------------------------------------------- /src/assets/assets-picked.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 10 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/assets/assets-result-403.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/assets/assets-result-404.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | 28 | 29 | 30 | 33 | 36 | 37 | -------------------------------------------------------------------------------- /src/assets/assets-result-wifi.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 19 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/assets/assets-setting-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/assets/assets-setting-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /src/assets/assets-slide-dashboard.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /src/assets/assets-slide-detail.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/assets/assets-slide-form.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/assets-slide-list.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/assets/assets-slide-logout.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/assets-t-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/assets/assets-tencent-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dianjie/tdesign-console/d68b7b286ec455f7d6000525e77d258a8016527a/src/assets/assets-tencent-logo.png -------------------------------------------------------------------------------- /src/components/color/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 25 | 26 | 34 | -------------------------------------------------------------------------------- /src/components/flow-image/index.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 92 | -------------------------------------------------------------------------------- /src/components/result/index.vue: -------------------------------------------------------------------------------- 1 | 11 | 47 | 99 | -------------------------------------------------------------------------------- /src/components/thumbnail/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 26 | 44 | -------------------------------------------------------------------------------- /src/components/trend/index.vue: -------------------------------------------------------------------------------- 1 | 23 | 49 | 50 | 100 | -------------------------------------------------------------------------------- /src/config/color.ts: -------------------------------------------------------------------------------- 1 | export type TColorToken = Record; 2 | export type TColorSeries = Record; 3 | 4 | // TODO: 中性色暂时固定 待tvision-color生成带色彩倾向的中性色 5 | export const LIGHT_CHART_COLORS = { 6 | textColor: 'rgba(0, 0, 0, 0.9)', 7 | placeholderColor: 'rgba(0, 0, 0, 0.35)', 8 | borderColor: '#dcdcdc', 9 | containerColor: '#fff', 10 | }; 11 | 12 | export const DARK_CHART_COLORS = { 13 | textColor: 'rgba(255, 255, 255, 0.9)', 14 | placeholderColor: 'rgba(255, 255, 255, 0.35)', 15 | borderColor: '#5e5e5e', 16 | containerColor: '#242424', 17 | }; 18 | 19 | export type TChartColor = typeof LIGHT_CHART_COLORS; 20 | 21 | export const DEFAULT_COLOR_OPTIONS = [ 22 | '#0052D9', 23 | '#0594FA', 24 | '#00A870', 25 | '#EBB105', 26 | '#ED7B2F', 27 | '#E34D59', 28 | '#ED49B4', 29 | '#834EC2', 30 | ]; 31 | -------------------------------------------------------------------------------- /src/config/global.ts: -------------------------------------------------------------------------------- 1 | export const prefix = 'tdesign-starter'; 2 | -------------------------------------------------------------------------------- /src/config/proxy.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | isRequestProxy: false, 3 | development: { 4 | // 开发环境接口请求 5 | apiUrl: '', 6 | urlPrefix: '/api', 7 | proxy: [['/api', 'https://saber.bladex.vip', false]], 8 | // 开发环境 cdn 路径 9 | cdn: '', 10 | }, 11 | test: { 12 | // 测试环境接口地址 13 | apiUrl: '', 14 | urlPrefix: '/api', 15 | proxy: [['/api', 'http://xxx.com', true]], 16 | // 测试环境 cdn 路径 17 | cdn: '', 18 | }, 19 | release: { 20 | // 正式环境接口地址 21 | apiUrl: '', 22 | urlPrefix: '/api', 23 | proxy: [['/api', 'http://xxx.com', true]], 24 | // 正式环境 cdn 路径 25 | cdn: '', 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /src/config/style.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | showFooter: true, 3 | isSidebarCompact: false, 4 | showBreadcrumb: false, 5 | menuAutoCollapsed: false, 6 | mode: 'light', 7 | layout: 'side', 8 | splitMenu: false, 9 | sideMode: 'light', 10 | isFooterAside: false, 11 | isSidebarFixed: true, 12 | isHeaderFixed: true, 13 | isUseTabsRouter: false, 14 | showHeader: true, 15 | brandTheme: '#0052D9', 16 | }; 17 | -------------------------------------------------------------------------------- /src/config/website.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 全局配置文件 3 | */ 4 | export default { 5 | clientId: 'saber', // 客户端id 6 | clientSecret: 'saber_secret', // 客户端密钥 7 | tokenHeader: 'Blade-Auth', 8 | tokenTime: 1800, 9 | tenantMode: true, // 是否开启租户模式 10 | tenantId: '000000', // 管理组租户编号 11 | captchaMode: false, // 是否开启验证码模式 12 | // http的status默认放行列表 13 | statusWhiteList: [], 14 | // 配置菜单的属性 15 | menu: { 16 | iconDefault: 'view-list', 17 | props: { 18 | // meata title 19 | title: 'name', 20 | path: 'path', 21 | icon: 'source', 22 | children: 'children', 23 | // 路由name 24 | code: 'code', 25 | }, 26 | }, 27 | flowDesign: { 28 | development: 'https://github.com/dianjie', 29 | test: '', 30 | release: '', 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /src/constants/index.ts: -------------------------------------------------------------------------------- 1 | // 标签类型 2 | type TagTheme = 'default' | 'success' | 'primary' | 'warning' | 'danger'; 3 | // 通知的优先级对应的标签类型 4 | export const NOTIFICATION_TYPES: Map = new Map([ 5 | ['low', 'primary'], 6 | ['middle', 'warning'], 7 | ['high', 'danger'], 8 | ]); 9 | 10 | // 通用请求头 11 | export enum ContentTypeEnum { 12 | Json = 'application/json;charset=UTF-8', 13 | FormURLEncoded = 'application/x-www-form-urlencoded;charset=UTF-8', 14 | FormData = 'multipart/form-data;charset=UTF-8', 15 | } 16 | -------------------------------------------------------------------------------- /src/directives/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Configure and register global directives 3 | */ 4 | import type { App } from 'vue'; 5 | 6 | import { setupPermissionDirective } from './permission'; 7 | 8 | export function setupGlobDirectives(app: App) { 9 | setupPermissionDirective(app); 10 | } 11 | -------------------------------------------------------------------------------- /src/directives/permission.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Global authority directive 3 | * Used for fine-grained control of component permissions 4 | * @Example v-auth="'message_add'" 5 | * @Example v-auth="['message_add', 'message_view']" 6 | */ 7 | import type { App, Directive, DirectiveBinding } from 'vue'; 8 | 9 | import { usePermission } from '@/hooks/web/usePermission'; 10 | 11 | function isAuth(el: Element, binding: any) { 12 | const { hasPermission } = usePermission(); 13 | 14 | const { value } = binding; 15 | if (!value) return; 16 | if (!hasPermission(value)) { 17 | el.parentNode?.removeChild(el); 18 | } 19 | } 20 | 21 | const mounted = (el: Element, binding: DirectiveBinding) => { 22 | isAuth(el, binding); 23 | }; 24 | 25 | const authDirective: Directive = { 26 | mounted, 27 | }; 28 | 29 | export function setupPermissionDirective(app: App) { 30 | app.directive('auth', authDirective); 31 | } 32 | 33 | export default authDirective; 34 | -------------------------------------------------------------------------------- /src/hooks/event/useWindowSizeFn.ts: -------------------------------------------------------------------------------- 1 | import { debounce } from 'lodash-es'; 2 | import { onMounted, onUnmounted } from 'vue'; 3 | 4 | interface WindowSizeOptions { 5 | immediate?: boolean; 6 | } 7 | 8 | interface Fn { 9 | (...arg: T[]): R; 10 | } 11 | 12 | export function useWindowSizeFn(fn: Fn, options?: WindowSizeOptions, wait = 150) { 13 | const handleSize: () => void = debounce(fn, wait); 14 | 15 | const start = () => { 16 | if (options && options.immediate) { 17 | fn(); 18 | } 19 | window.addEventListener('resize', handleSize); 20 | }; 21 | 22 | const stop = () => { 23 | window.removeEventListener('resize', handleSize); 24 | }; 25 | 26 | onMounted(() => { 27 | start(); 28 | }); 29 | 30 | onUnmounted(() => { 31 | stop(); 32 | }); 33 | return [start, stop]; 34 | } 35 | -------------------------------------------------------------------------------- /src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | import * as echarts from 'echarts/core'; 2 | import { onMounted, onUnmounted, type Ref, ref, type ShallowRef, shallowRef } from 'vue'; 3 | 4 | /** 5 | * eChart hook 6 | * @param domId 7 | */ 8 | export const useChart = (domId: string): ShallowRef => { 9 | let chartContainer: HTMLCanvasElement; 10 | const selfChart = shallowRef(); 11 | const updateContainer = () => { 12 | selfChart.value.resize({ 13 | width: chartContainer.clientWidth, 14 | height: chartContainer.clientHeight, 15 | }); 16 | }; 17 | 18 | onMounted(() => { 19 | if (!chartContainer) { 20 | chartContainer = document.getElementById(domId) as HTMLCanvasElement; 21 | } 22 | selfChart.value = echarts.init(chartContainer); 23 | }); 24 | 25 | window.addEventListener('resize', updateContainer, false); 26 | 27 | onUnmounted(() => { 28 | window.removeEventListener('resize', updateContainer); 29 | }); 30 | 31 | return selfChart; 32 | }; 33 | 34 | /** 35 | * counter utils 36 | * @param duration 37 | * @returns 38 | */ 39 | export const useCounter = (duration = 60): [Ref, () => void] => { 40 | let intervalTimer: ReturnType; 41 | onUnmounted(() => { 42 | clearInterval(intervalTimer); 43 | }); 44 | const countDown = ref(0); 45 | 46 | return [ 47 | countDown, 48 | () => { 49 | countDown.value = duration; 50 | intervalTimer = setInterval(() => { 51 | if (countDown.value > 0) { 52 | countDown.value -= 1; 53 | } else { 54 | clearInterval(intervalTimer); 55 | countDown.value = 0; 56 | } 57 | }, 1000); 58 | }, 59 | ]; 60 | }; 61 | -------------------------------------------------------------------------------- /src/hooks/setting/useSetting.ts: -------------------------------------------------------------------------------- 1 | import { computed } from 'vue'; 2 | 3 | import { prefix } from '@/config/global'; 4 | import { useSettingStore } from '@/store'; 5 | 6 | export function useSetting() { 7 | const settingStore = useSettingStore(); 8 | 9 | const getTableHeaderAffixedTop = computed(() => { 10 | return settingStore.isUseTabsRouter ? 48 : 0; 11 | }); 12 | 13 | const getLayoutContainer = () => { 14 | return document.querySelector(`.${prefix}-layout`); 15 | }; 16 | 17 | return { 18 | getTableHeaderAffixedTop, 19 | getLayoutContainer, 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /src/hooks/web/useDesign.ts: -------------------------------------------------------------------------------- 1 | import { prefix } from '@/config/global'; 2 | 3 | export function useDesign(scope?: string) { 4 | return { 5 | prefixCls: `${prefix}-${scope}`, 6 | prefixVar: prefix, 7 | tableVar: `${prefix}-table-form-container`, 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /src/hooks/web/usePermission.ts: -------------------------------------------------------------------------------- 1 | import { intersection } from 'lodash-es'; 2 | 3 | import { usePermissionStore } from '@/store/modules/permission'; 4 | import { useUserStore } from '@/store/modules/user'; 5 | import { isArray } from '@/utils/is'; 6 | 7 | export function usePermission() { 8 | const permissionStore = usePermissionStore(); 9 | const { getRoleName } = useUserStore(); 10 | 11 | function hasPermission(value?: string | string[], def = true): boolean { 12 | if (!value) { 13 | return def; 14 | } 15 | const allCodeList = permissionStore.getPermCodeList as string[]; 16 | if (!isArray(value)) { 17 | return allCodeList.includes(value); 18 | } 19 | return (intersection(value, allCodeList) as string[]).length > 0; 20 | } 21 | 22 | function hasRole(value?: string | string[], def = true): boolean { 23 | if (!value) { 24 | return def; 25 | } 26 | const roles = getRoleName.split(','); 27 | if (!isArray(value)) { 28 | return roles.includes(value); 29 | } 30 | return (intersection(value, roles) as string[]).length > 0; 31 | } 32 | 33 | return { hasPermission, hasRole }; 34 | } 35 | -------------------------------------------------------------------------------- /src/hooks/web/useRequset.ts: -------------------------------------------------------------------------------- 1 | import type { Ref } from 'vue'; 2 | import { ref, unref } from 'vue'; 3 | 4 | import type { BasicPagination } from '@/api/model/baseModel'; 5 | 6 | export function useRequset(fn: Fn, formData: any, callback: Fn, hasPagination = true) { 7 | const data = ref([]); 8 | const pagination: Ref = ref({ 9 | pageSize: 10, 10 | total: 0, 11 | current: 1, 12 | }); 13 | const dataLoading = ref(false); 14 | 15 | const fetchData = async (newFormData?: any) => { 16 | dataLoading.value = true; 17 | try { 18 | if (hasPagination) { 19 | const { pageSize, current } = unref(pagination); 20 | const list = await fn(current, pageSize, newFormData || formData); 21 | data.value = list.records; 22 | pagination.value = { 23 | ...pagination.value, 24 | total: list.total, 25 | }; 26 | } else { 27 | const list = await fn(newFormData || formData); 28 | data.value = list; 29 | } 30 | } catch (e) { 31 | console.log(e); 32 | } finally { 33 | dataLoading.value = false; 34 | callback(); 35 | } 36 | }; 37 | 38 | function setData(list: any[]) { 39 | data.value = list; 40 | } 41 | 42 | function setPagination(paginationData: BasicPagination) { 43 | pagination.value = paginationData; 44 | } 45 | 46 | function setDataLoading(loading: boolean) { 47 | dataLoading.value = loading; 48 | } 49 | 50 | return { fetchData, data, dataLoading, pagination, setData, setPagination, setDataLoading }; 51 | } 52 | -------------------------------------------------------------------------------- /src/layouts/blank.vue: -------------------------------------------------------------------------------- 1 | 6 | 13 | -------------------------------------------------------------------------------- /src/layouts/components/Breadcrumb.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 38 | 43 | -------------------------------------------------------------------------------- /src/layouts/components/Content.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 50 | 61 | -------------------------------------------------------------------------------- /src/layouts/components/Footer.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 16 | -------------------------------------------------------------------------------- /src/layouts/components/FrameBlank.vue: -------------------------------------------------------------------------------- 1 | 4 | 11 | -------------------------------------------------------------------------------- /src/layouts/components/LayoutHeader.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 37 | -------------------------------------------------------------------------------- /src/layouts/components/LayoutSideNav.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 41 | -------------------------------------------------------------------------------- /src/layouts/components/Search.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 55 | 131 | -------------------------------------------------------------------------------- /src/layouts/frame/index.vue: -------------------------------------------------------------------------------- 1 | 8 | 26 | -------------------------------------------------------------------------------- /src/layouts/frame/useFrameKeepAlive.ts: -------------------------------------------------------------------------------- 1 | import { uniqBy } from 'lodash-es'; 2 | import { computed, toRaw, unref } from 'vue'; 3 | import { useRouter } from 'vue-router'; 4 | 5 | import type { AppRouteRecordRaw } from '@/router/types'; 6 | import { useSettingStore, useTabsRouterStore } from '@/store'; 7 | 8 | export function useFrameKeepAlive() { 9 | const router = useRouter(); 10 | const { currentRoute } = router; 11 | const { isUseTabsRouter } = useSettingStore(); 12 | const tabStore = useTabsRouterStore(); 13 | const getFramePages = computed(() => { 14 | const ret = getAllFramePages(toRaw(router.getRoutes()) as unknown as AppRouteRecordRaw[]) || []; 15 | return ret; 16 | }); 17 | 18 | const getOpenTabList = computed((): string[] => { 19 | return tabStore.tabRouters.reduce((prev: string[], next) => { 20 | if (next.meta && Reflect.has(next.meta, 'frameSrc')) { 21 | prev.push(next.name as string); 22 | } 23 | return prev; 24 | }, []); 25 | }); 26 | 27 | function getAllFramePages(routes: AppRouteRecordRaw[]): AppRouteRecordRaw[] { 28 | let res: AppRouteRecordRaw[] = []; 29 | for (const route of routes) { 30 | const { meta: { frameSrc } = {}, children } = route; 31 | if (frameSrc) { 32 | res.push(route); 33 | } 34 | if (children && children.length) { 35 | res.push(...getAllFramePages(children)); 36 | } 37 | } 38 | res = uniqBy(res, 'name'); 39 | return res; 40 | } 41 | 42 | function showIframe(item: AppRouteRecordRaw) { 43 | return item.name === unref(currentRoute).name; 44 | } 45 | 46 | function hasRenderFrame(name: string) { 47 | if (!unref(isUseTabsRouter)) { 48 | return router.currentRoute.value.name === name; 49 | } 50 | return unref(getOpenTabList).includes(name); 51 | } 52 | 53 | return { hasRenderFrame, getFramePages, showIframe, getAllFramePages }; 54 | } 55 | -------------------------------------------------------------------------------- /src/layouts/index.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import 'tdesign-vue-next/es/style/index.css'; 2 | import '@/style/index.less'; 3 | import './permission'; 4 | 5 | import TDesign from 'tdesign-vue-next'; 6 | import { createApp } from 'vue'; 7 | 8 | import { setupGlobDirectives } from '@/directives'; 9 | 10 | import App from './App.vue'; 11 | import router from './router'; 12 | import { store } from './store'; 13 | 14 | const app = createApp(App); 15 | 16 | app.use(TDesign); 17 | app.use(store); 18 | app.use(router); 19 | 20 | // Register global directive 21 | setupGlobDirectives(app); 22 | 23 | app.mount('#app'); 24 | -------------------------------------------------------------------------------- /src/pages/login/components/Header.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 37 | 38 | 63 | -------------------------------------------------------------------------------- /src/pages/login/index.vue: -------------------------------------------------------------------------------- 1 | 25 | 30 | 44 | 45 | 48 | -------------------------------------------------------------------------------- /src/pages/redirect/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 32 | -------------------------------------------------------------------------------- /src/pages/result/403/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | -------------------------------------------------------------------------------- /src/pages/result/404/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/pages/result/500/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | -------------------------------------------------------------------------------- /src/pages/result/browser-incompatible/index.vue: -------------------------------------------------------------------------------- 1 | 21 | 26 | 30 | 31 | 75 | -------------------------------------------------------------------------------- /src/pages/result/fail/index.vue: -------------------------------------------------------------------------------- 1 | 12 | 17 | 44 | -------------------------------------------------------------------------------- /src/pages/result/maintenance/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 15 | -------------------------------------------------------------------------------- /src/pages/result/network-error/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | 18 | -------------------------------------------------------------------------------- /src/pages/result/success/index.vue: -------------------------------------------------------------------------------- 1 | 12 | 17 | 44 | -------------------------------------------------------------------------------- /src/permission.ts: -------------------------------------------------------------------------------- 1 | import 'nprogress/nprogress.css'; // progress bar style 2 | 3 | import NProgress from 'nprogress'; // progress bar 4 | import type { RouteRecordRaw } from 'vue-router'; 5 | 6 | import router from '@/router'; 7 | import { BASE_HOME, LOGIN_PATH, LONGIN_NAME, PAGE_NOT_FOUND_NAME } from '@/router/constant'; 8 | import { getPermissionStore, getUserStore } from '@/store'; 9 | 10 | NProgress.configure({ showSpinner: false }); 11 | 12 | function getRoute(url: string) { 13 | const queryIndex = url.indexOf('?'); 14 | const hasQuery = queryIndex !== -1; 15 | const paramArr = hasQuery ? url.slice(queryIndex + 1).split('&') : []; 16 | const params = {}; 17 | paramArr.forEach((param) => { 18 | const [key, val] = param.split('='); 19 | params[key] = decodeURIComponent(val); 20 | }); 21 | return { 22 | path: hasQuery ? url.slice(0, queryIndex) : url, 23 | query: params, 24 | }; 25 | } 26 | 27 | router.beforeEach(async (to, from, next) => { 28 | NProgress.start(); 29 | 30 | const userStore = getUserStore(); 31 | const permissionStore = getPermissionStore(); 32 | const { whiteListRouters } = permissionStore; 33 | 34 | const { token } = userStore; 35 | 36 | if (whiteListRouters.includes(to.path)) { 37 | next(); 38 | return; 39 | } 40 | 41 | // token does not exist 42 | if (!token) { 43 | // You can access without permission. You need to set the routing meta.ignoreAuth to true 44 | if (to.meta.ignoreAuth) { 45 | next(); 46 | return; 47 | } 48 | 49 | if (to.name === LONGIN_NAME) { 50 | next(); 51 | return; 52 | } 53 | 54 | // redirect login page 55 | const redirectData: { path: string; replace: boolean; query?: Recordable } = { 56 | path: LOGIN_PATH, 57 | replace: true, 58 | }; 59 | if (to.path) { 60 | redirectData.query = { 61 | redirect: to.path, 62 | }; 63 | } 64 | next(redirectData); 65 | return; 66 | } 67 | 68 | if (to.name === LONGIN_NAME) { 69 | next(BASE_HOME); 70 | return; 71 | } 72 | 73 | // Jump to the 404 page after processing the login 74 | if (from.path === LOGIN_PATH && to.name === PAGE_NOT_FOUND_NAME && to.fullPath !== BASE_HOME) { 75 | next(BASE_HOME); 76 | return; 77 | } 78 | 79 | if (permissionStore.getIsDynamicAddedRoute) { 80 | next(); 81 | return; 82 | } 83 | 84 | const routes = await permissionStore.buildRoutesAction(); 85 | 86 | routes.forEach((route) => { 87 | router.addRoute(route as unknown as RouteRecordRaw); 88 | }); 89 | permissionStore.setDynamicAddedRoute(true); 90 | 91 | if (to.name === PAGE_NOT_FOUND_NAME) { 92 | const toRoute = to.redirectedFrom ?? to; 93 | // 动态添加路由后,此处应当重定向到fullPath,否则会加载404页面内容 94 | next({ path: toRoute.fullPath, replace: true, query: toRoute.query }); 95 | } else { 96 | const redirectPath = (from.query.redirect || to.path) as string; 97 | const redirect = decodeURIComponent(redirectPath); 98 | const nextData = to.path === redirect ? { ...to, replace: true } : getRoute(redirect); 99 | next(nextData); 100 | } 101 | }); 102 | 103 | router.afterEach(() => { 104 | NProgress.done(); 105 | }); 106 | -------------------------------------------------------------------------------- /src/router/constant.ts: -------------------------------------------------------------------------------- 1 | export const LOGIN_PATH = '/login'; 2 | export const BASE_HOME = '/dashboard/workbench'; 3 | export const USER_HOME = '/basic-info/index'; 4 | 5 | export const LONGIN_NAME = 'Login'; 6 | 7 | export const REDIRECT_NAME = 'Redirect'; 8 | 9 | export const PARENT_LAYOUT_NAME = 'ParentLayout'; 10 | 11 | export const PAGE_NOT_FOUND_NAME = 'PageNotFound'; 12 | 13 | export const NOTFOUND = () => import('@/pages/result/404/index.vue'); 14 | 15 | /** 16 | * @description: default layout 17 | */ 18 | export const LAYOUT = () => import('@/layouts/index.vue'); 19 | 20 | /** 21 | * @description: parent-layout 22 | */ 23 | export const getParentLayout = (_name?: string) => { 24 | return () => 25 | new Promise((resolve) => { 26 | resolve({ 27 | name: PARENT_LAYOUT_NAME, 28 | }); 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { uniq } from 'lodash-es'; 2 | import { createRouter, createWebHashHistory, type RouteRecordRaw } from 'vue-router'; 3 | 4 | import type { AppRouteRecordRaw } from '@/router/types'; 5 | 6 | import { BASE_HOME, LONGIN_NAME } from './constant'; 7 | 8 | interface ModuleType { 9 | default: []; 10 | } 11 | // 自动导入modules文件夹下所有ts文件 12 | const modules = import.meta.glob('./modules/**/*.ts', { eager: true }); 13 | 14 | // 路由暂存 15 | const routeModuleList: AppRouteRecordRaw[] = []; 16 | 17 | Object.keys(modules).forEach((key) => { 18 | const mod = modules[key].default || {}; 19 | const modList = Array.isArray(mod) ? [...mod] : [mod]; 20 | routeModuleList.push(...modList); 21 | }); 22 | 23 | // 关于单层路由,meta 中设置 { single: true } 即可为单层路由,{ hidden: true } 即可在侧边栏隐藏该路由 24 | 25 | // 存放动态路由 26 | export const asyncRouterList: AppRouteRecordRaw[] = [...routeModuleList]; 27 | 28 | // 存放固定的路由 29 | const defaultRouterList: AppRouteRecordRaw[] = [ 30 | { 31 | path: '/login', 32 | name: LONGIN_NAME, 33 | component: () => import('@/pages/login/index.vue'), 34 | }, 35 | { 36 | path: '/', 37 | name: 'home', 38 | redirect: BASE_HOME, 39 | component: () => import('@/layouts/blank.vue'), 40 | }, 41 | { 42 | path: '/:w+', 43 | name: '404Page', 44 | redirect: '/result/404', 45 | }, 46 | ]; 47 | 48 | export const allRoutes: AppRouteRecordRaw[] = [...defaultRouterList, ...asyncRouterList]; 49 | 50 | export const getRoutesExpanded = () => { 51 | const expandedRoutes: Array = []; 52 | 53 | allRoutes.forEach((item) => { 54 | if (item.meta && item.meta.expanded) { 55 | expandedRoutes.push(item.path); 56 | } 57 | if (item.children && item.children.length > 0) { 58 | item.children 59 | .filter((child) => child.meta && child.meta.expanded) 60 | .forEach((child: AppRouteRecordRaw) => { 61 | expandedRoutes.push(item.path); 62 | expandedRoutes.push(`${item.path}/${child.path}`); 63 | }); 64 | } 65 | }); 66 | return uniq(expandedRoutes); 67 | }; 68 | 69 | export const getActive = (maxLevel = 3): string => { 70 | // 非组件内调用必须通过Router实例获取当前路由 71 | const route = router.currentRoute.value; 72 | 73 | if (!route.path) { 74 | return ''; 75 | } 76 | return route.path 77 | .split('/') 78 | .filter((_item: string, index: number) => index <= maxLevel && index > 0) 79 | .map((item: string) => `/${item}`) 80 | .join(''); 81 | }; 82 | 83 | const router = createRouter({ 84 | history: createWebHashHistory(), 85 | routes: allRoutes as unknown as RouteRecordRaw[], 86 | scrollBehavior() { 87 | return { 88 | el: '#app', 89 | top: 0, 90 | behavior: 'smooth', 91 | }; 92 | }, 93 | }); 94 | 95 | export default router; 96 | -------------------------------------------------------------------------------- /src/router/modules/base.ts: -------------------------------------------------------------------------------- 1 | import DashboardIcon from '@/assets/assets-slide-dashboard.svg'; 2 | 3 | import { LAYOUT } from '../constant'; 4 | 5 | export default [ 6 | { 7 | path: '/dashboard', 8 | component: LAYOUT, 9 | redirect: '/dashboard/base', 10 | name: 'dashboard', 11 | meta: { title: '仪表盘', icon: DashboardIcon }, 12 | children: [ 13 | { 14 | path: 'workbench', 15 | name: 'DashboardWorkbench', 16 | component: () => import('@/pages/dashboard/workbench/index.vue'), 17 | meta: { title: '工作台' }, 18 | }, 19 | ], 20 | }, 21 | ]; 22 | -------------------------------------------------------------------------------- /src/router/modules/components.ts: -------------------------------------------------------------------------------- 1 | import { LAYOUT, PAGE_NOT_FOUND_NAME, REDIRECT_NAME } from '../constant'; 2 | 3 | export default [ 4 | { 5 | path: '/redirect', 6 | component: LAYOUT, 7 | name: 'RedirectTo', 8 | meta: { 9 | title: REDIRECT_NAME, 10 | hideBreadcrumb: true, 11 | hideMenu: true, 12 | }, 13 | children: [ 14 | { 15 | path: '/redirect/:path(.*)', 16 | name: REDIRECT_NAME, 17 | component: () => import('@/pages/redirect/index.vue'), 18 | meta: { 19 | title: REDIRECT_NAME, 20 | hideBreadcrumb: true, 21 | }, 22 | }, 23 | ], 24 | }, 25 | { 26 | path: '/result', 27 | name: 'result', 28 | component: LAYOUT, 29 | redirect: '/result/success', 30 | meta: { title: '结果页', icon: 'check-circle' }, 31 | children: [ 32 | { 33 | path: 'success', 34 | name: 'ResultSuccess', 35 | component: () => import('@/pages/result/success/index.vue'), 36 | meta: { title: '成功页' }, 37 | }, 38 | { 39 | path: 'fail', 40 | name: 'ResultFail', 41 | component: () => import('@/pages/result/fail/index.vue'), 42 | meta: { title: '失败页' }, 43 | }, 44 | { 45 | path: 'network-error', 46 | name: 'ResultNetworkError', 47 | component: () => import('@/pages/result/network-error/index.vue'), 48 | meta: { title: '网络异常' }, 49 | }, 50 | { 51 | path: '403', 52 | name: 'Result403', 53 | component: () => import('@/pages/result/403/index.vue'), 54 | meta: { title: '无权限' }, 55 | }, 56 | { 57 | path: '404', 58 | name: PAGE_NOT_FOUND_NAME, 59 | component: () => import('@/pages/result/404/index.vue'), 60 | meta: { title: '访问页面不存在页' }, 61 | }, 62 | { 63 | path: '500', 64 | name: 'Result500', 65 | component: () => import('@/pages/result/500/index.vue'), 66 | meta: { title: '服务器出错页' }, 67 | }, 68 | { 69 | path: 'browser-incompatible', 70 | name: 'ResultBrowserIncompatible', 71 | component: () => import('@/pages/result/browser-incompatible/index.vue'), 72 | meta: { title: '浏览器不兼容页' }, 73 | }, 74 | { 75 | path: 'maintenance', 76 | name: 'ResultMaintenance', 77 | component: () => import('@/pages/result/maintenance/index.vue'), 78 | meta: { title: '系统维护页' }, 79 | }, 80 | ], 81 | }, 82 | ]; 83 | -------------------------------------------------------------------------------- /src/router/modules/others.ts: -------------------------------------------------------------------------------- 1 | import LogoutIcon from '@/assets/assets-slide-logout.svg'; 2 | 3 | import { LAYOUT } from '../constant'; 4 | 5 | export default [ 6 | { 7 | path: '/basic-info', 8 | name: 'basicInfo', 9 | component: LAYOUT, 10 | redirect: '/basic-info/index', 11 | meta: { title: '个人中心', icon: 'user-circle' }, 12 | children: [ 13 | { 14 | path: 'index', 15 | name: 'UserIndex', 16 | component: () => import('@/views/system/userInfo.vue'), 17 | meta: { title: '个人信息' }, 18 | }, 19 | ], 20 | }, 21 | { 22 | path: '/loginRedirect', 23 | name: 'loginRedirect', 24 | redirect: '/login', 25 | meta: { title: '登录页', icon: LogoutIcon }, 26 | component: () => import('@/layouts/blank.vue'), 27 | children: [ 28 | { 29 | path: 'index', 30 | redirect: '/login', 31 | component: () => import('@/layouts/blank.vue'), 32 | meta: { title: '登录中心' }, 33 | }, 34 | ], 35 | }, 36 | ]; 37 | -------------------------------------------------------------------------------- /src/router/modules/process/leava.ts: -------------------------------------------------------------------------------- 1 | import { LAYOUT } from '@/router/constant'; 2 | 3 | export default [ 4 | { 5 | path: '/work/process/leave', 6 | name: 'leaveProces', 7 | component: LAYOUT, 8 | redirect: '/work/process/leave/form', 9 | children: [ 10 | { 11 | path: 'form/:processDefinitionId', 12 | name: 'leaveStart', 13 | component: () => import('@/views/process/leave/form.vue'), 14 | meta: { title: '发起请假流程' }, 15 | }, 16 | { 17 | path: 'handle/:taskId/:processInstanceId/:businessId', 18 | name: 'leaveHandle', 19 | component: () => import('@/views/process/leave/handle.vue'), 20 | meta: { title: '处理请假流程' }, 21 | }, 22 | { 23 | path: 'detail/:processInstanceId/:businessId', 24 | name: 'leaveDetail', 25 | component: () => import('@/views/process/leave/detail.vue'), 26 | meta: { title: '请假流程详情' }, 27 | }, 28 | ], 29 | }, 30 | ]; 31 | -------------------------------------------------------------------------------- /src/router/types.ts: -------------------------------------------------------------------------------- 1 | import type { defineComponent } from 'vue'; 2 | import type { RouteMeta, RouteRecordRaw } from 'vue-router'; 3 | 4 | export type Component = 5 | | ReturnType 6 | | (() => Promise) 7 | | (() => Promise); 8 | 9 | // @ts-ignore 10 | export interface AppRouteRecordRaw extends Omit { 11 | id?: string; 12 | name: string; 13 | meta?: RouteMeta; 14 | // 图标 15 | source?: string; 16 | code?: string; 17 | parentId?: string; 18 | component?: Component | string; 19 | components?: Component; 20 | children?: AppRouteRecordRaw[]; 21 | hasChildren?: boolean; 22 | // 是否打开新页面 23 | isOpen?: number; 24 | props?: Recordable; 25 | fullPath?: string; 26 | } 27 | 28 | export interface MenuTag { 29 | type?: 'primary' | 'error' | 'warn' | 'success'; 30 | content?: string; 31 | dot?: boolean; 32 | } 33 | 34 | export interface Menu { 35 | name: string; 36 | 37 | icon?: string; 38 | 39 | path: string; 40 | 41 | // path contains param, auto assignment. 42 | paramPath?: string; 43 | 44 | disabled?: boolean; 45 | 46 | children?: Menu[]; 47 | 48 | orderNo?: number; 49 | 50 | roles?: any; 51 | 52 | meta?: Partial; 53 | 54 | tag?: MenuTag; 55 | 56 | hideMenu?: boolean; 57 | } 58 | 59 | export interface MenuModule { 60 | orderNo?: number; 61 | menu: Menu; 62 | } 63 | 64 | // export type AppRouteModule = RouteModule | AppRouteRecordRaw; 65 | export type AppRouteModule = AppRouteRecordRaw; 66 | -------------------------------------------------------------------------------- /src/store/index.ts: -------------------------------------------------------------------------------- 1 | import { createPinia } from 'pinia'; 2 | import { createPersistedState } from 'pinia-plugin-persistedstate'; 3 | 4 | const store = createPinia(); 5 | store.use(createPersistedState()); 6 | 7 | export { store }; 8 | 9 | export * from './modules/dict'; 10 | export * from './modules/notification'; 11 | export * from './modules/permission'; 12 | export * from './modules/setting'; 13 | export * from './modules/tabs-router'; 14 | export * from './modules/user'; 15 | 16 | export default store; 17 | -------------------------------------------------------------------------------- /src/store/modules/dict.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia'; 2 | 3 | import { getDictData } from '@/api/system/dict'; 4 | import { store } from '@/store'; 5 | import { changeDictDataType } from '@/utils'; 6 | 7 | export const useDictStore = defineStore('dict', { 8 | state: () => ({ 9 | flow: [], 10 | flowRoutes: [], 11 | }), 12 | getters: { 13 | getFlowDict: (state) => { 14 | return state.flow || []; 15 | }, 16 | getFlowRoutes: (state) => { 17 | return state.flowRoutes || []; 18 | }, 19 | }, 20 | actions: { 21 | setFlowDict(arr: any[]) { 22 | this.flow = changeDictDataType(arr); 23 | }, 24 | setFlowRoutes(arr: any[]) { 25 | this.flowRoutes = arr.map((item) => { 26 | return { 27 | routeKey: `${item.code}_${item.dictKey}`, 28 | routeValue: item.remark, 29 | }; 30 | }); 31 | }, 32 | async getServerFlowDict() { 33 | const data = await getDictData('flow'); 34 | this.setFlowDict(data); 35 | this.setFlowRoutes(data); 36 | }, 37 | }, 38 | persist: true, 39 | }); 40 | 41 | export function getDictStore() { 42 | return useDictStore(store); 43 | } 44 | -------------------------------------------------------------------------------- /src/store/modules/notification.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia'; 2 | 3 | import type { NotificationItem } from '@/types/interface'; 4 | 5 | const msgData = [ 6 | { 7 | id: '123', 8 | content: '腾讯大厦一楼改造施工项目 已通过审核!', 9 | type: '合同动态', 10 | status: true, 11 | collected: false, 12 | date: '2021-01-01 08:00', 13 | quality: 'high', 14 | }, 15 | { 16 | id: '124', 17 | content: '三季度生产原材料采购项目 开票成功!', 18 | type: '票务动态', 19 | status: true, 20 | collected: false, 21 | date: '2021-01-01 08:00', 22 | quality: 'low', 23 | }, 24 | { 25 | id: '125', 26 | content: '2021-01-01 10:00的【国家电网线下签约】会议即将开始,请提前10分钟前往 会议室1 进行签到!', 27 | type: '会议通知', 28 | status: true, 29 | collected: false, 30 | date: '2021-01-01 08:00', 31 | quality: 'middle', 32 | }, 33 | { 34 | id: '126', 35 | content: '一季度生产原材料采购项目 开票成功!', 36 | type: '票务动态', 37 | status: true, 38 | collected: false, 39 | date: '2021-01-01 08:00', 40 | quality: 'low', 41 | }, 42 | ]; 43 | 44 | type MsgDataType = typeof msgData; 45 | 46 | export const useNotificationStore = defineStore('notification', { 47 | state: () => ({ 48 | msgData, 49 | }), 50 | getters: { 51 | unreadMsg: (state) => state.msgData.filter((item: NotificationItem) => item.status), 52 | readMsg: (state) => state.msgData.filter((item: NotificationItem) => !item.status), 53 | }, 54 | actions: { 55 | setMsgData(data: MsgDataType) { 56 | this.msgData = data; 57 | }, 58 | }, 59 | persist: true, 60 | }); 61 | -------------------------------------------------------------------------------- /src/style/index.less: -------------------------------------------------------------------------------- 1 | @import './font-family.less'; 2 | @import './reset.less'; 3 | -------------------------------------------------------------------------------- /src/style/variables.less: -------------------------------------------------------------------------------- 1 | // 公共前缀在vite.config注入了 2 | 3 | // 颜色、尺寸、阴影、圆角、字体 variables 请参考 https://tdesign.tencent.com/starter/docs/vue/design-token 4 | // 响应式断点 5 | @screen-sm: 768px; 6 | @screen-md: 992px; 7 | @screen-lg: 1200px; 8 | @screen-xl: 1400px; 9 | 10 | @screen-sm-min: @screen-sm; 11 | @screen-md-min: @screen-md; 12 | @screen-lg-min: @screen-lg; 13 | @screen-xl-min: @screen-xl; 14 | 15 | @screen-sm-max: calc(@screen-md-min - 1px); 16 | @screen-md-max: calc(@screen-lg-min - 1px); 17 | @screen-lg-max: calc(@screen-xl-min - 1px); 18 | 19 | // 动画 20 | @anim-time-fn-easing: cubic-bezier(0.38, 0, 0.24, 1); 21 | @anim-time-fn-ease-out: cubic-bezier(0, 0, 0.15, 1); 22 | @anim-time-fn-ease-in: cubic-bezier(0.82, 0, 1, 0.9); 23 | @anim-duration-base: 0.2s; 24 | @anim-duration-moderate: 0.24s; 25 | @anim-duration-slow: 0.28s; 26 | -------------------------------------------------------------------------------- /src/types/axios.d.ts: -------------------------------------------------------------------------------- 1 | import type { AxiosRequestConfig } from 'axios'; 2 | 3 | export type ErrorMessageMode = 'none' | 'dialog' | 'message' | undefined; 4 | 5 | /** 6 | * Axios请求配置 7 | */ 8 | export interface RequestOptions { 9 | /** 10 | * 接口地址 11 | * 12 | * 例: http://www.baidu.com/api 13 | */ 14 | apiUrl?: string; 15 | /** 16 | * 是否自动添加接口前缀 17 | * 18 | * 例: http://www.baidu.com/api 19 | * urlPrefix: 'api' 20 | */ 21 | isJoinPrefix?: boolean; 22 | /** 23 | * 接口前缀 24 | */ 25 | urlPrefix?: string; 26 | /** 27 | * POST请求的时候添加参数到Url中 28 | */ 29 | joinParamsToUrl?: boolean; 30 | /** 31 | * 格式化提交参数时间 32 | */ 33 | formatDate?: boolean; 34 | /** 35 | * 是否需要对响应数据进行处理 36 | */ 37 | isTransformResponse?: boolean; 38 | /** 39 | * 是否返回原生响应头 40 | * 41 | * 例: 需要获取响应头时使用该属性 42 | */ 43 | isReturnNativeResponse?: boolean; 44 | ignoreRepeatRequest?: boolean; 45 | /** 46 | * 自动对请求添加时间戳参数 47 | */ 48 | joinTime?: boolean; 49 | /** 50 | * 是否携带Token 51 | */ 52 | withToken?: boolean; 53 | /** 54 | * 重试配置 55 | */ 56 | retry?: { 57 | /** 58 | * 重试次数 59 | */ 60 | count: number; 61 | /** 62 | * 隔多久重试 63 | * 64 | * 单位: 毫秒 65 | */ 66 | delay: number; 67 | }; 68 | /** 69 | * 接口级节流 70 | * 71 | * 单位: 毫秒 72 | */ 73 | throttle?: { 74 | delay: number; 75 | }; 76 | /** 77 | * 接口级防抖 78 | * 79 | * 单位: 毫秒 80 | */ 81 | debounce?: { 82 | delay: number; 83 | }; 84 | // Error message prompt type 85 | errorMessageMode?: ErrorMessageMode; 86 | authorization?: boolean; 87 | clearEmptyParam?: boolean; 88 | } 89 | 90 | export interface Result { 91 | code: number; 92 | success: boolean; 93 | msg: string; 94 | data: T; 95 | } 96 | 97 | export interface AxiosRequestConfigRetry extends AxiosRequestConfig { 98 | retryCount?: number; 99 | } 100 | 101 | // multipart/form-data: upload file 102 | export interface UploadFileParams { 103 | // Other parameters 104 | data?: Recordable; 105 | // File parameter interface field name 106 | name?: string; 107 | // file name 108 | file: File | Blob; 109 | // file name 110 | filename?: string; 111 | [key: string]: any; 112 | } 113 | -------------------------------------------------------------------------------- /src/types/env.d.ts: -------------------------------------------------------------------------------- 1 | export interface ImportMetaEnv { 2 | readonly VITE_IS_REQUEST_PROXY: string; 3 | readonly VITE_API_URL: string; 4 | readonly VITE_API_URL_PREFIX: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/types/globals.d.ts: -------------------------------------------------------------------------------- 1 | // 通用声明 2 | 3 | // Vue 4 | declare module '*.vue' { 5 | import { DefineComponent } from 'vue'; 6 | 7 | const component: DefineComponent<{}, {}, any>; 8 | export default component; 9 | } 10 | 11 | declare type ClassName = { [className: string]: any } | ClassName[] | string; 12 | 13 | declare module '*.svg' { 14 | const CONTENT: string; 15 | export default CONTENT; 16 | } 17 | 18 | declare type Recordable = Record; 19 | 20 | declare type StrOrNum = number | string; 21 | -------------------------------------------------------------------------------- /src/types/index.d.ts: -------------------------------------------------------------------------------- 1 | declare interface Fn { 2 | (...arg: T[]): R; 3 | } 4 | 5 | declare type TargetContext = '_self' | '_blank'; 6 | 7 | declare type Nullable = T | undefined | null; 8 | -------------------------------------------------------------------------------- /src/types/interface.d.ts: -------------------------------------------------------------------------------- 1 | import { LocationQueryRaw, RouteRecordName } from 'vue-router'; 2 | 3 | export interface RouteMeta { 4 | title?: string | Record; 5 | icon?: string; 6 | expanded?: boolean; 7 | orderNo?: number; 8 | hidden?: boolean; 9 | hiddenBreadcrumb?: boolean; 10 | single?: boolean; 11 | keepAlive?: boolean; 12 | frameSrc?: string; 13 | frameBlank?: boolean; 14 | } 15 | 16 | export interface MenuRoute { 17 | path: string; 18 | title?: string; 19 | icon?: 20 | | string 21 | | { 22 | render: () => void; 23 | }; 24 | redirect?: string; 25 | children: MenuRoute[]; 26 | meta: any; 27 | } 28 | 29 | export type ModeType = 'dark' | 'light'; 30 | 31 | export interface NotificationItem { 32 | id: string; 33 | content: string; 34 | type: string; 35 | status: boolean; 36 | collected: boolean; 37 | date: string; 38 | quality: string; 39 | } 40 | 41 | export interface TRouterInfo { 42 | path: string; 43 | query?: LocationQueryRaw; 44 | routeIdx?: number; 45 | title?: string; 46 | name?: RouteRecordName; 47 | isAlive?: boolean; 48 | isHome?: boolean; 49 | meta?: any; 50 | } 51 | 52 | export interface TTabRouterType { 53 | isRefreshing: boolean; 54 | tabRouterList: Array; 55 | } 56 | 57 | export interface TTabRemoveOptions { 58 | value: TabValue; 59 | index: number; 60 | e: MouseEvent; 61 | } 62 | 63 | export interface TreeDefaultRow { 64 | parentId?: string; 65 | [key: string]: any; 66 | } 67 | -------------------------------------------------------------------------------- /src/types/vue-router.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | 3 | declare module 'vue-router' { 4 | interface RouteMeta extends Record { 5 | orderNo?: number; 6 | // title 7 | title: string; 8 | // dynamic router level. 9 | dynamicLevel?: number; 10 | // dynamic router real route path (For performance). 11 | realPath?: string; 12 | // Whether to ignore permissions 13 | ignoreAuth?: boolean; 14 | // role info 15 | roles?: RoleEnum[]; 16 | // Whether not to cache 17 | ignoreKeepAlive?: boolean; 18 | // Is it fixed on tab 19 | affix?: boolean; 20 | // icon on tab 21 | icon?: string; 22 | frameSrc?: string; 23 | // current page transition 24 | transitionName?: string; 25 | // Whether the route has been dynamically added 26 | hideBreadcrumb?: boolean; 27 | // Hide submenu 28 | hideChildrenInMenu?: boolean; 29 | // Carrying parameters 30 | carryParam?: boolean; 31 | // Used internally to mark single-level menus 32 | single?: boolean; 33 | // Currently active menu 34 | currentActiveMenu?: string; 35 | // Never show in tab 36 | hideTab?: boolean; 37 | // Never show in menu 38 | hideMenu?: boolean; 39 | isLink?: boolean; 40 | // only build for Menu 41 | ignoreRoute?: boolean; 42 | // Hide path for children 43 | hidePathForChildren?: boolean; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/utils/charts.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs'; 2 | 3 | /** 4 | * 获取表头数据 5 | * 6 | * @export 7 | * @param {string[]} dateTime 8 | * @param {number} divideNum 9 | * @returns {string[]} 10 | */ 11 | export function getDateArray(dateTime: string[] = [], divideNum = 10): string[] { 12 | const timeArray: string[] = []; 13 | if (dateTime.length > 0) { 14 | for (let i = 0; i < divideNum; i++) { 15 | const dateAbsTime: number = (new Date(dateTime[1]).getTime() - new Date(dateTime[0]).getTime()) / divideNum; 16 | const enhandTime: number = new Date(dateTime[0]).getTime() + dateAbsTime * i; 17 | timeArray.push(dayjs(enhandTime).format('YYYY-MM-DD')); 18 | } 19 | } 20 | 21 | return timeArray; 22 | } 23 | 24 | /** 25 | * 获取随机数 26 | * 27 | * @param {number} [num=100] 28 | * @returns 29 | * 30 | * @memberOf DashboardBase 31 | */ 32 | export function getRandomArray(num = 100): number { 33 | let resultNum = Number((Math.random() * num).toFixed(0)); 34 | 35 | if (resultNum <= 1) { 36 | resultNum = 1; 37 | } 38 | 39 | return resultNum; 40 | } 41 | -------------------------------------------------------------------------------- /src/utils/date.ts: -------------------------------------------------------------------------------- 1 | // 获取常用时间 2 | import dayjs from 'dayjs'; 3 | 4 | export const LAST_7_DAYS = [ 5 | dayjs().subtract(7, 'day').format('YYYY-MM-DD'), 6 | dayjs().subtract(1, 'day').format('YYYY-MM-DD'), 7 | ]; 8 | 9 | export const LAST_30_DAYS = [ 10 | dayjs().subtract(30, 'day').format('YYYY-MM-DD'), 11 | dayjs().subtract(1, 'day').format('YYYY-MM-DD'), 12 | ]; 13 | -------------------------------------------------------------------------------- /src/utils/file/base64Conver.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description: base64 to blob 3 | */ 4 | export function dataURLtoBlob(base64Buf: string): Blob { 5 | const arr = base64Buf.split(','); 6 | const typeItem = arr[0]; 7 | const mime = typeItem.match(/:(.*?);/)![1]; 8 | const bstr = atob(arr[1]); 9 | let n = bstr.length; 10 | const u8arr = new Uint8Array(n); 11 | while (n--) { 12 | u8arr[n] = bstr.charCodeAt(n); 13 | } 14 | return new Blob([u8arr], { type: mime }); 15 | } 16 | 17 | /** 18 | * img url to base64 19 | * @param url 20 | */ 21 | export function urlToBase64(url: string, mineType?: string): Promise { 22 | return new Promise((resolve, reject) => { 23 | let canvas = document.createElement('CANVAS') as Nullable; 24 | const ctx = canvas!.getContext('2d'); 25 | 26 | const img = new Image(); 27 | img.crossOrigin = ''; 28 | /* eslint consistent-return: off */ 29 | img.onload = () => { 30 | if (!canvas || !ctx) { 31 | return reject(); 32 | } 33 | canvas.height = img.height; 34 | canvas.width = img.width; 35 | ctx.drawImage(img, 0, 0); 36 | const dataURL = canvas.toDataURL(mineType || 'image/png'); 37 | canvas = null; 38 | resolve(dataURL); 39 | }; 40 | img.src = url; 41 | }); 42 | } 43 | -------------------------------------------------------------------------------- /src/utils/helper/flowHelper.ts: -------------------------------------------------------------------------------- 1 | import website from '@/config/website'; 2 | 3 | import { isEmpty, isNullOrUnDef } from '../is'; 4 | 5 | export const getFinalFlowCategory = (val: StrOrNum) => { 6 | return isNullOrUnDef(val) || isEmpty(val) ? '' : `flow_${val}`; 7 | }; 8 | 9 | export const getFlowConfig = () => { 10 | const env = import.meta.env.MODE || 'development'; 11 | return website.flowDesign[env]; 12 | }; 13 | 14 | export const getFlowDesignUrl = () => { 15 | const config = getFlowConfig(); 16 | return config || ''; 17 | }; 18 | 19 | export const flowRoute = (routes: any[], key: string) => { 20 | const data = routes.filter((d) => { 21 | return d.routeKey === key; 22 | }); 23 | return data.length === 0 ? [] : data[0].routeValue; 24 | }; 25 | -------------------------------------------------------------------------------- /src/utils/is.ts: -------------------------------------------------------------------------------- 1 | const { toString } = Object.prototype; 2 | 3 | export function is(val: unknown, type: string) { 4 | return toString.call(val) === `[object ${type}]`; 5 | } 6 | 7 | export function isDef(val?: T): val is T { 8 | return typeof val !== 'undefined'; 9 | } 10 | 11 | export function isUnDef(val?: T): val is T { 12 | return !isDef(val); 13 | } 14 | 15 | export function isObject(val: any): val is Record { 16 | return val !== null && is(val, 'Object'); 17 | } 18 | 19 | export function isEmpty(val: T): val is T { 20 | if (isArray(val) || isString(val)) { 21 | return val.length === 0; 22 | } 23 | 24 | if (val instanceof Map || val instanceof Set) { 25 | return val.size === 0; 26 | } 27 | 28 | if (isObject(val)) { 29 | return Object.keys(val).length === 0; 30 | } 31 | 32 | return false; 33 | } 34 | 35 | export function isDate(val: unknown): val is Date { 36 | return is(val, 'Date'); 37 | } 38 | 39 | export function isNull(val: unknown): val is null { 40 | return val === null; 41 | } 42 | 43 | export function isNullAndUnDef(val: unknown): val is null | undefined { 44 | return isUnDef(val) && isNull(val); 45 | } 46 | 47 | export function isNullOrUnDef(val: unknown): val is null | undefined { 48 | return isUnDef(val) || isNull(val); 49 | } 50 | 51 | export function isNumber(val: unknown): val is number { 52 | return is(val, 'Number'); 53 | } 54 | 55 | export function isPromise(val: unknown): val is Promise { 56 | return is(val, 'Promise') && isObject(val) && isFunction(val.then) && isFunction(val.catch); 57 | } 58 | 59 | export function isString(val: unknown): val is string { 60 | return is(val, 'String'); 61 | } 62 | 63 | export function isFunction(val: unknown): val is Function { 64 | return typeof val === 'function'; 65 | } 66 | 67 | export function isBoolean(val: unknown): val is boolean { 68 | return is(val, 'Boolean'); 69 | } 70 | 71 | export function isRegExp(val: unknown): val is RegExp { 72 | return is(val, 'RegExp'); 73 | } 74 | 75 | export function isArray(val: any): val is Array { 76 | return val && Array.isArray(val); 77 | } 78 | 79 | export function isWindow(val: any): val is Window { 80 | return typeof window !== 'undefined' && is(val, 'Window'); 81 | } 82 | 83 | export function isElement(val: unknown): val is Element { 84 | return isObject(val) && !!val.tagName; 85 | } 86 | 87 | export function isMap(val: unknown): val is Map { 88 | return is(val, 'Map'); 89 | } 90 | 91 | export const isServer = typeof window === 'undefined'; 92 | 93 | export const isClient = !isServer; 94 | 95 | export function isUrl(path: string): boolean { 96 | const reg = 97 | // eslint-disable-next-line no-useless-escape 98 | /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/; 99 | return reg.test(path); 100 | } 101 | -------------------------------------------------------------------------------- /src/utils/request/AxiosCancel.ts: -------------------------------------------------------------------------------- 1 | import type { AxiosRequestConfig, Canceler } from 'axios'; 2 | import axios from 'axios'; 3 | import { isFunction } from 'lodash-es'; 4 | 5 | // 存储请求与取消令牌的键值对列表 6 | let pendingMap = new Map(); 7 | 8 | /** 9 | * 获取请求Url 10 | * @param config 11 | */ 12 | export const getPendingUrl = (config: AxiosRequestConfig) => [config.method, config.url].join('&'); 13 | 14 | /** 15 | * @description 请求管理器 16 | */ 17 | export class AxiosCanceler { 18 | /** 19 | * 添加请求到列表中 20 | * @param config 21 | */ 22 | addPending(config: AxiosRequestConfig) { 23 | this.removePending(config); 24 | const url = getPendingUrl(config); 25 | config.cancelToken = 26 | config.cancelToken || 27 | new axios.CancelToken((cancel) => { 28 | if (!pendingMap.has(url)) { 29 | // 如果当前没有相同请求就添加 30 | pendingMap.set(url, cancel); 31 | } 32 | }); 33 | } 34 | 35 | /** 36 | * 移除现有的所有请求 37 | */ 38 | removeAllPending() { 39 | pendingMap.forEach((cancel) => { 40 | if (cancel && isFunction(cancel)) cancel(); 41 | }); 42 | pendingMap.clear(); 43 | } 44 | 45 | /** 46 | * 移除指定请求 47 | * @param config 48 | */ 49 | removePending(config: AxiosRequestConfig) { 50 | const url = getPendingUrl(config); 51 | 52 | if (pendingMap.has(url)) { 53 | // If there is a current request identifier in pending, 54 | // the current request needs to be cancelled and removed 55 | const cancel = pendingMap.get(url); 56 | if (cancel) cancel(url); 57 | pendingMap.delete(url); 58 | } 59 | } 60 | 61 | /** 62 | * 重置 63 | */ 64 | reset() { 65 | pendingMap = new Map(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/utils/request/AxiosTransform.ts: -------------------------------------------------------------------------------- 1 | import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; 2 | import { AxiosError } from 'axios'; 3 | 4 | import type { RequestOptions, Result } from '@/types/axios'; 5 | 6 | /** 7 | * @description 创建Axios实例配置 8 | */ 9 | export interface CreateAxiosOptions extends AxiosRequestConfig { 10 | /** 11 | * 请求验证方案 12 | * 13 | * https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes 14 | */ 15 | authenticationScheme?: string; 16 | /** 17 | * 请求数据处理 18 | */ 19 | transform?: AxiosTransform; 20 | /** 21 | * 请求配置 22 | */ 23 | requestOptions?: RequestOptions; 24 | } 25 | 26 | /** 27 | * Axios请求数据处理 抽象类 28 | */ 29 | export abstract class AxiosTransform { 30 | /** 31 | * 请求前钩子 32 | */ 33 | beforeRequestHook?: (config: AxiosRequestConfig, options: RequestOptions) => AxiosRequestConfig; 34 | 35 | /** 36 | * 数据处理前钩子 37 | */ 38 | transformRequestHook?: (res: AxiosResponse, options: RequestOptions) => T; 39 | 40 | /** 41 | * 请求失败钩子 42 | */ 43 | requestCatchHook?: (e: Error | AxiosError, options: RequestOptions) => Promise; 44 | 45 | /** 46 | * 请求拦截器 47 | */ 48 | requestInterceptors?: (config: AxiosRequestConfig, options: CreateAxiosOptions) => AxiosRequestConfig; 49 | 50 | /** 51 | * 响应拦截器 52 | */ 53 | responseInterceptors?: (res: AxiosResponse) => AxiosResponse; 54 | 55 | /** 56 | * 请求拦截器错误处理 57 | */ 58 | requestInterceptorsCatch?: (error: AxiosError) => void; 59 | 60 | /** 61 | * 响应拦截器错误处理 62 | */ 63 | responseInterceptorsCatch?: (error: AxiosError, instance: AxiosInstance) => void; 64 | } 65 | -------------------------------------------------------------------------------- /src/utils/request/checkStatus.ts: -------------------------------------------------------------------------------- 1 | import { DialogPlugin, MessagePlugin } from 'tdesign-vue-next'; 2 | 3 | import { getUserStore } from '@/store'; 4 | import type { ErrorMessageMode } from '@/types/axios'; 5 | 6 | export function checkStatus(status: number, msg: string, errorMessageMode: ErrorMessageMode = 'message'): void { 7 | let errMessage = ''; 8 | const userStore = getUserStore(); 9 | 10 | switch (status) { 11 | case 400: 12 | errMessage = `${msg}`; 13 | break; 14 | // 401: Not logged in 15 | // Jump to the login page if not logged in, and carry the path of the current page 16 | // Return to the current page after successful login. This step needs to be operated on the login page. 17 | case 401: 18 | userStore.logout(true); 19 | errMessage = msg || '用户没有权限(令牌、用户名、密码错误)!'; 20 | break; 21 | case 403: 22 | errMessage = '用户得到授权,但是访问是被禁止的。!'; 23 | break; 24 | // 404请求不存在 25 | case 404: 26 | errMessage = '网络请求错误,未找到该资源!'; 27 | break; 28 | case 405: 29 | errMessage = '网络请求错误,请求方法未允许!'; 30 | break; 31 | case 408: 32 | errMessage = '网络请求超时!'; 33 | break; 34 | case 500: 35 | errMessage = msg || '服务器错误,请联系管理员!'; 36 | break; 37 | case 501: 38 | errMessage = '网络未实现!'; 39 | break; 40 | case 502: 41 | errMessage = '网络错误!'; 42 | break; 43 | case 503: 44 | errMessage = '服务不可用,服务器暂时过载或维护!'; 45 | break; 46 | case 504: 47 | errMessage = '网络超时!'; 48 | break; 49 | case 505: 50 | errMessage = 'http版本不支持该请求!'; 51 | break; 52 | default: 53 | } 54 | 55 | if (errMessage) { 56 | if (errorMessageMode === 'dialog') { 57 | const alertDia = DialogPlugin.alert({ 58 | header: '错误提示', 59 | body: errMessage, 60 | onConfirm: () => { 61 | alertDia.hide(); 62 | }, 63 | onClose: () => { 64 | alertDia.hide(); 65 | }, 66 | }); 67 | } else if (errorMessageMode === 'message') { 68 | MessagePlugin.error(errMessage); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/utils/request/utils.ts: -------------------------------------------------------------------------------- 1 | import { isObject, isString } from 'lodash-es'; 2 | 3 | const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'; 4 | 5 | export function joinTimestamp(join: boolean, restful: T): T extends true ? string : Recordable; 6 | 7 | export function joinTimestamp(join: boolean, restful = false): string | object { 8 | if (!join) { 9 | return restful ? '' : {}; 10 | } 11 | const now = new Date().getTime(); 12 | if (restful) { 13 | return `?_t=${now}`; 14 | } 15 | return { _t: now }; 16 | } 17 | 18 | // 格式化提交参数时间 19 | export function formatRequestDate(params: Recordable) { 20 | if (Object.prototype.toString.call(params) !== '[object Object]') { 21 | return; 22 | } 23 | 24 | for (const key in params) { 25 | // eslint-disable-next-line no-underscore-dangle 26 | if (params[key] && params[key]._isAMomentObject) { 27 | params[key] = params[key].format(DATE_TIME_FORMAT); 28 | } 29 | if (isString(key)) { 30 | const value = params[key]; 31 | if (value) { 32 | try { 33 | params[key] = isString(value) ? value.trim() : value; 34 | } catch (error: any) { 35 | throw new Error(error); 36 | } 37 | } 38 | } 39 | if (isObject(params[key])) { 40 | formatRequestDate(params[key]); 41 | } 42 | } 43 | } 44 | 45 | // 将对象转为Url参数 46 | export function setObjToUrlParams(baseUrl: string, obj: Recordable): string { 47 | let parameters = ''; 48 | for (const key in obj) { 49 | parameters += `${key}=${encodeURIComponent(obj[key])}&`; 50 | } 51 | parameters = parameters.replace(/&$/, ''); 52 | return /\?$/.test(baseUrl) ? baseUrl + parameters : baseUrl.replace(/\/?$/, '?') + parameters; 53 | } 54 | -------------------------------------------------------------------------------- /src/viewsBusiness/authority/constant/apiscope/authority.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | title: '权限名称', 17 | colKey: 'scopeName', 18 | ellipsis: true, 19 | width: 200, 20 | }, 21 | { 22 | title: '权限编号', 23 | colKey: 'resourceCode', 24 | ellipsis: true, 25 | width: 200, 26 | }, 27 | { 28 | title: '权限路径', 29 | colKey: 'scopePath', 30 | ellipsis: true, 31 | width: 200, 32 | }, 33 | { 34 | title: '接口类型', 35 | colKey: 'scopeTypeName', 36 | ellipsis: true, 37 | width: 200, 38 | }, 39 | { 40 | fixed: 'right', 41 | width: 180, 42 | colKey: 'op', 43 | title: '操作', 44 | align: 'center', 45 | }, 46 | ]; 47 | -------------------------------------------------------------------------------- /src/viewsBusiness/authority/constant/apiscope/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'serial-number', 4 | title: '序号', 5 | width: 80, 6 | align: 'center', 7 | fixed: 'left', 8 | }, 9 | { 10 | title: '菜单名称', 11 | colKey: 'name', 12 | ellipsis: true, 13 | width: 200, 14 | }, 15 | { 16 | title: '路由地址', 17 | colKey: 'path', 18 | ellipsis: true, 19 | width: 200, 20 | }, 21 | { 22 | title: '菜单图标', 23 | colKey: 'source', 24 | width: 80, 25 | ellipsis: true, 26 | align: 'center', 27 | }, 28 | { 29 | title: '菜单编号', 30 | colKey: 'code', 31 | width: 150, 32 | ellipsis: true, 33 | }, 34 | { 35 | title: '菜单别名', 36 | colKey: 'alias', 37 | width: 80, 38 | ellipsis: true, 39 | }, 40 | { 41 | title: '菜单排序', 42 | width: 80, 43 | colKey: 'sort', 44 | ellipsis: true, 45 | }, 46 | { 47 | fixed: 'right', 48 | width: 80, 49 | colKey: 'op', 50 | title: '操作', 51 | align: 'center', 52 | }, 53 | ]; 54 | -------------------------------------------------------------------------------- /src/viewsBusiness/authority/constant/datascope/authority.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | title: '权限名称', 17 | colKey: 'scopeName', 18 | ellipsis: true, 19 | width: 200, 20 | }, 21 | { 22 | title: '权限编号', 23 | colKey: 'resourceCode', 24 | ellipsis: true, 25 | width: 200, 26 | }, 27 | { 28 | title: '权限字段', 29 | colKey: 'scopeColumn', 30 | ellipsis: true, 31 | width: 200, 32 | }, 33 | { 34 | title: '规则类型', 35 | colKey: 'scopeTypeName', 36 | ellipsis: true, 37 | width: 200, 38 | }, 39 | { 40 | fixed: 'right', 41 | width: 180, 42 | colKey: 'op', 43 | title: '操作', 44 | align: 'center', 45 | }, 46 | ]; 47 | 48 | // 相应的规则类型对应的默认权限字段 49 | export const SCOPE_COLUMN = [ 50 | { 51 | dictKey: 1, 52 | dictValue: '-', 53 | }, 54 | { 55 | dictKey: 2, 56 | dictValue: 'create_user', 57 | }, 58 | { 59 | dictKey: 3, 60 | dictValue: 'create_dept', 61 | }, 62 | { 63 | dictKey: 4, 64 | dictValue: 'create_dept', 65 | }, 66 | { 67 | dictKey: 5, 68 | dictValue: '', 69 | }, 70 | ]; 71 | -------------------------------------------------------------------------------- /src/viewsBusiness/authority/constant/datascope/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'serial-number', 4 | title: '序号', 5 | width: 80, 6 | align: 'center', 7 | fixed: 'left', 8 | }, 9 | { 10 | title: '菜单名称', 11 | colKey: 'name', 12 | ellipsis: true, 13 | width: 200, 14 | }, 15 | { 16 | title: '路由地址', 17 | colKey: 'path', 18 | ellipsis: true, 19 | width: 200, 20 | }, 21 | { 22 | title: '菜单图标', 23 | colKey: 'source', 24 | width: 80, 25 | ellipsis: true, 26 | align: 'center', 27 | }, 28 | { 29 | title: '菜单编号', 30 | colKey: 'code', 31 | width: 150, 32 | ellipsis: true, 33 | }, 34 | { 35 | title: '菜单别名', 36 | colKey: 'alias', 37 | width: 80, 38 | ellipsis: true, 39 | }, 40 | { 41 | title: '菜单排序', 42 | width: 80, 43 | colKey: 'sort', 44 | ellipsis: true, 45 | }, 46 | { 47 | fixed: 'right', 48 | width: 80, 49 | colKey: 'op', 50 | title: '操作', 51 | align: 'center', 52 | }, 53 | ]; 54 | -------------------------------------------------------------------------------- /src/viewsBusiness/authority/constant/role/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | colKey: 'roleName', 17 | title: '角色名称', 18 | }, 19 | { 20 | colKey: 'tenantId', 21 | title: '所属租户', 22 | }, 23 | { 24 | colKey: 'roleAlias', 25 | title: '角色别名', 26 | }, 27 | { 28 | colKey: 'sort', 29 | title: '角色排序', 30 | }, 31 | { 32 | fixed: 'right', 33 | width: 180, 34 | colKey: 'op', 35 | title: '操作', 36 | align: 'center', 37 | }, 38 | ]; 39 | -------------------------------------------------------------------------------- /src/viewsBusiness/flow/constant/follow/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'serial-number', 4 | title: '序号', 5 | width: 80, 6 | align: 'center', 7 | fixed: 'left', 8 | }, 9 | { 10 | title: '执行id', 11 | colKey: 'executionId', 12 | }, 13 | { 14 | title: '流程key', 15 | colKey: 'processDefinitionKey', 16 | }, 17 | { 18 | title: '实例id', 19 | colKey: 'processInstanceId', 20 | }, 21 | { 22 | title: '状态', 23 | colKey: 'suspensionState', 24 | }, 25 | { 26 | title: '发起人', 27 | colKey: 'startUser', 28 | }, 29 | { 30 | title: '开始时间', 31 | colKey: 'startTime', 32 | }, 33 | { 34 | fixed: 'right', 35 | width: 100, 36 | colKey: 'op', 37 | title: '操作', 38 | align: 'center', 39 | }, 40 | ]; 41 | -------------------------------------------------------------------------------- /src/viewsBusiness/flow/constant/manager/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'serial-number', 4 | title: '序号', 5 | width: 80, 6 | align: 'center', 7 | fixed: 'left', 8 | }, 9 | { 10 | title: '租户编号', 11 | colKey: 'tenantId', 12 | }, 13 | { 14 | title: '流程主键', 15 | colKey: 'id', 16 | }, 17 | { 18 | title: '流程标识', 19 | colKey: 'key', 20 | }, 21 | { 22 | title: '流程名称', 23 | colKey: 'name', 24 | }, 25 | { 26 | title: '流程分类', 27 | colKey: 'categoryName', 28 | }, 29 | { 30 | title: '流程版本', 31 | colKey: 'version', 32 | }, 33 | { 34 | title: '状态', 35 | colKey: 'suspensionState', 36 | }, 37 | { 38 | title: '部署时间', 39 | colKey: 'deploymentTime', 40 | }, 41 | { 42 | fixed: 'right', 43 | width: 210, 44 | colKey: 'op', 45 | title: '操作', 46 | align: 'center', 47 | }, 48 | ]; 49 | -------------------------------------------------------------------------------- /src/viewsBusiness/flow/constant/model/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'serial-number', 4 | title: '序号', 5 | width: 80, 6 | align: 'center', 7 | fixed: 'left', 8 | }, 9 | { 10 | title: '模型主键', 11 | colKey: 'id', 12 | }, 13 | { 14 | title: '模型标识', 15 | colKey: 'modelKey', 16 | }, 17 | { 18 | title: '模型名称', 19 | colKey: 'name', 20 | }, 21 | { 22 | title: '流程版本', 23 | colKey: 'version', 24 | }, 25 | { 26 | title: '创建时间', 27 | colKey: 'created', 28 | }, 29 | { 30 | title: '更新时间', 31 | colKey: 'lastUpdated', 32 | }, 33 | { 34 | fixed: 'right', 35 | width: 210, 36 | colKey: 'op', 37 | title: '操作', 38 | align: 'center', 39 | }, 40 | ]; 41 | -------------------------------------------------------------------------------- /src/viewsBusiness/monitor/log/constant/api/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'serial-number', 4 | title: '序号', 5 | width: 80, 6 | align: 'center', 7 | fixed: 'left', 8 | }, 9 | { 10 | title: '服务id', 11 | colKey: 'serviceId', 12 | }, 13 | { 14 | title: '服务host', 15 | colKey: 'serverHost', 16 | }, 17 | { 18 | title: '服务ip', 19 | colKey: 'serverIp', 20 | }, 21 | { 22 | title: '软件环境', 23 | colKey: 'env', 24 | }, 25 | { 26 | title: '请求方法', 27 | colKey: 'method', 28 | }, 29 | { 30 | title: '请求接口', 31 | colKey: 'requestUri', 32 | }, 33 | { 34 | title: '日志时间', 35 | colKey: 'createTime', 36 | }, 37 | { 38 | fixed: 'right', 39 | width: 80, 40 | colKey: 'op', 41 | title: '操作', 42 | align: 'center', 43 | }, 44 | ]; 45 | -------------------------------------------------------------------------------- /src/viewsBusiness/monitor/log/constant/error/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'serial-number', 4 | title: '序号', 5 | width: 80, 6 | align: 'center', 7 | fixed: 'left', 8 | }, 9 | { 10 | title: '服务id', 11 | colKey: 'serviceId', 12 | }, 13 | { 14 | title: '服务host', 15 | colKey: 'serverHost', 16 | }, 17 | { 18 | title: '服务ip', 19 | colKey: 'serverIp', 20 | }, 21 | { 22 | title: '软件环境', 23 | colKey: 'env', 24 | }, 25 | { 26 | title: '请求方法', 27 | colKey: 'method', 28 | }, 29 | { 30 | title: '请求接口', 31 | colKey: 'requestUri', 32 | }, 33 | { 34 | title: '日志时间', 35 | colKey: 'createTime', 36 | }, 37 | { 38 | fixed: 'right', 39 | width: 80, 40 | colKey: 'op', 41 | title: '操作', 42 | align: 'center', 43 | }, 44 | ]; 45 | -------------------------------------------------------------------------------- /src/viewsBusiness/monitor/log/constant/usual/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'serial-number', 4 | title: '序号', 5 | width: 80, 6 | align: 'center', 7 | fixed: 'left', 8 | }, 9 | { 10 | title: '服务id', 11 | colKey: 'serviceId', 12 | }, 13 | { 14 | title: '服务host', 15 | colKey: 'serverHost', 16 | }, 17 | { 18 | title: '服务ip', 19 | colKey: 'serverIp', 20 | }, 21 | { 22 | title: '软件环境', 23 | colKey: 'env', 24 | }, 25 | { 26 | title: '日志级别', 27 | colKey: 'logLevel', 28 | }, 29 | { 30 | title: '日志id', 31 | colKey: 'logId', 32 | }, 33 | { 34 | title: '请求接口', 35 | colKey: 'requestUri', 36 | }, 37 | { 38 | title: '请求接口', 39 | colKey: 'requestUri', 40 | }, 41 | { 42 | title: '日志时间', 43 | colKey: 'createTime', 44 | }, 45 | { 46 | fixed: 'right', 47 | width: 80, 48 | colKey: 'op', 49 | title: '操作', 50 | align: 'center', 51 | }, 52 | ]; 53 | -------------------------------------------------------------------------------- /src/viewsBusiness/resource/components/attach/DialogUpload.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 114 | -------------------------------------------------------------------------------- /src/viewsBusiness/resource/constant/attach/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | title: '附件地址', 17 | colKey: 'link', 18 | }, 19 | { 20 | title: '附件域名', 21 | colKey: 'domainUrl', 22 | }, 23 | { 24 | title: '附件名称', 25 | colKey: 'name', 26 | }, 27 | { 28 | title: '附件原名', 29 | colKey: 'originalName', 30 | }, 31 | { 32 | title: '附件拓展名', 33 | colKey: 'extension', 34 | }, 35 | { 36 | title: '附件大小(KB)', 37 | colKey: 'attachSize', 38 | }, 39 | { 40 | fixed: 'right', 41 | width: 100, 42 | colKey: 'op', 43 | title: '操作', 44 | align: 'center', 45 | }, 46 | ]; 47 | -------------------------------------------------------------------------------- /src/viewsBusiness/resource/constant/oss/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | title: '分类', 17 | colKey: 'category', 18 | }, 19 | { 20 | title: '资源编号', 21 | colKey: 'ossCode', 22 | }, 23 | { 24 | title: '资源地址', 25 | colKey: 'endpoint', 26 | }, 27 | { 28 | title: '空间名', 29 | colKey: 'bucketName', 30 | }, 31 | { 32 | title: 'accessKey', 33 | colKey: 'accessKey', 34 | }, 35 | { 36 | title: 'secretKey', 37 | colKey: 'secretKey', 38 | }, 39 | { 40 | title: '是否启用', 41 | colKey: 'statusName', 42 | }, 43 | { 44 | fixed: 'right', 45 | width: 280, 46 | colKey: 'op', 47 | title: '操作', 48 | align: 'center', 49 | }, 50 | ]; 51 | -------------------------------------------------------------------------------- /src/viewsBusiness/resource/constant/sms/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | title: '分类', 17 | colKey: 'category', 18 | }, 19 | { 20 | title: '资源编号', 21 | colKey: 'smsCode', 22 | }, 23 | { 24 | title: '模版ID', 25 | colKey: 'templateId', 26 | }, 27 | { 28 | title: 'accessKey', 29 | colKey: 'accessKey', 30 | }, 31 | { 32 | title: '短信签名', 33 | colKey: 'signName', 34 | }, 35 | { 36 | title: '是否启用', 37 | colKey: 'statusName', 38 | }, 39 | { 40 | fixed: 'right', 41 | width: 280, 42 | colKey: 'op', 43 | title: '操作', 44 | align: 'center', 45 | }, 46 | ]; 47 | -------------------------------------------------------------------------------- /src/viewsBusiness/system/components/user/platfrom/DialogForm.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 120 | -------------------------------------------------------------------------------- /src/viewsBusiness/system/constant/client/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | title: '应用ID', 17 | colKey: 'clientId', 18 | }, 19 | { 20 | title: '应用密钥', 21 | colKey: 'clientSecret', 22 | }, 23 | { 24 | title: '授权类型', 25 | colKey: 'authorizedGrantTypes', 26 | }, 27 | { 28 | title: '授权范围', 29 | colKey: 'scope', 30 | }, 31 | { 32 | title: '令牌秒数', 33 | colKey: 'accessTokenValidity', 34 | }, 35 | { 36 | fixed: 'right', 37 | width: 180, 38 | colKey: 'op', 39 | title: '操作', 40 | align: 'center', 41 | }, 42 | ]; 43 | 44 | export const scopeOptions = [ 45 | { label: '全选', checkAll: true }, 46 | { value: 'refresh_token', label: 'refresh_token' }, 47 | { value: 'password', label: 'password' }, 48 | { value: 'authorization_code', label: 'authorization_code' }, 49 | { value: 'captcha', label: 'captcha' }, 50 | { value: 'social', label: 'social' }, 51 | ]; 52 | -------------------------------------------------------------------------------- /src/viewsBusiness/system/constant/dept/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | title: '机构名称', 17 | colKey: 'deptName', 18 | ellipsis: true, 19 | width: 200, 20 | }, 21 | { 22 | title: '所属租户', 23 | colKey: 'tenantId', 24 | ellipsis: true, 25 | width: 200, 26 | }, 27 | { 28 | title: '机构全称', 29 | colKey: 'fullName', 30 | ellipsis: true, 31 | width: 200, 32 | }, 33 | { 34 | title: '机构类型', 35 | colKey: 'deptCategory', 36 | width: 150, 37 | ellipsis: true, 38 | }, 39 | { 40 | title: '排序', 41 | width: 80, 42 | colKey: 'sort', 43 | ellipsis: true, 44 | }, 45 | { 46 | fixed: 'right', 47 | width: 180, 48 | colKey: 'op', 49 | title: '操作', 50 | align: 'center', 51 | }, 52 | ]; 53 | -------------------------------------------------------------------------------- /src/viewsBusiness/system/constant/dict/child/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | title: '字典编号', 17 | colKey: 'code', 18 | }, 19 | { 20 | title: '字典名称', 21 | colKey: 'dictValue', 22 | }, 23 | { 24 | title: '字典键值', 25 | colKey: 'dictKey', 26 | }, 27 | { 28 | title: '字典排序', 29 | colKey: 'sort', 30 | }, 31 | { 32 | title: '封存', 33 | colKey: 'isSealed', 34 | }, 35 | { 36 | fixed: 'right', 37 | width: 250, 38 | colKey: 'op', 39 | title: '操作', 40 | align: 'center', 41 | }, 42 | ]; 43 | -------------------------------------------------------------------------------- /src/viewsBusiness/system/constant/dict/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | title: '字典编号', 17 | colKey: 'code', 18 | }, 19 | { 20 | title: '字典名称', 21 | colKey: 'dictValue', 22 | }, 23 | { 24 | title: '字典排序', 25 | colKey: 'sort', 26 | }, 27 | { 28 | title: '封存', 29 | colKey: 'isSealed', 30 | }, 31 | { 32 | fixed: 'right', 33 | width: 240, 34 | colKey: 'op', 35 | title: '操作', 36 | align: 'center', 37 | }, 38 | ]; 39 | -------------------------------------------------------------------------------- /src/viewsBusiness/system/constant/dictbiz/child/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | title: '字典编号', 17 | colKey: 'code', 18 | }, 19 | { 20 | title: '字典名称', 21 | colKey: 'dictValue', 22 | }, 23 | { 24 | title: '字典键值', 25 | colKey: 'dictKey', 26 | }, 27 | { 28 | title: '字典排序', 29 | colKey: 'sort', 30 | }, 31 | { 32 | title: '封存', 33 | colKey: 'isSealed', 34 | }, 35 | { 36 | fixed: 'right', 37 | width: 250, 38 | colKey: 'op', 39 | title: '操作', 40 | align: 'center', 41 | }, 42 | ]; 43 | -------------------------------------------------------------------------------- /src/viewsBusiness/system/constant/dictbiz/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | title: '字典编号', 17 | colKey: 'code', 18 | }, 19 | { 20 | title: '字典名称', 21 | colKey: 'dictValue', 22 | }, 23 | { 24 | title: '字典排序', 25 | colKey: 'sort', 26 | }, 27 | { 28 | title: '封存', 29 | colKey: 'isSealed', 30 | }, 31 | { 32 | fixed: 'right', 33 | width: 240, 34 | colKey: 'op', 35 | title: '操作', 36 | align: 'center', 37 | }, 38 | ]; 39 | -------------------------------------------------------------------------------- /src/viewsBusiness/system/constant/menu/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | title: '菜单名称', 17 | colKey: 'name', 18 | ellipsis: true, 19 | width: 200, 20 | }, 21 | { 22 | title: '路由地址', 23 | colKey: 'path', 24 | ellipsis: true, 25 | width: 200, 26 | }, 27 | { 28 | title: '菜单图标', 29 | colKey: 'source', 30 | width: 80, 31 | ellipsis: true, 32 | align: 'center', 33 | }, 34 | { 35 | title: '菜单编号', 36 | colKey: 'code', 37 | width: 150, 38 | ellipsis: true, 39 | }, 40 | { 41 | title: '新窗口', 42 | colKey: 'isOpen', 43 | width: 80, 44 | ellipsis: true, 45 | }, 46 | { 47 | title: '菜单排序', 48 | width: 80, 49 | colKey: 'sort', 50 | ellipsis: true, 51 | }, 52 | { 53 | fixed: 'right', 54 | width: 180, 55 | colKey: 'op', 56 | title: '操作', 57 | align: 'center', 58 | }, 59 | ]; 60 | -------------------------------------------------------------------------------- /src/viewsBusiness/system/constant/param/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | title: '参数名称', 17 | colKey: 'paramName', 18 | }, 19 | { 20 | title: '参数键名', 21 | colKey: 'paramKey', 22 | }, 23 | { 24 | title: '参数键值', 25 | colKey: 'paramValue', 26 | }, 27 | { 28 | fixed: 'right', 29 | width: 180, 30 | colKey: 'op', 31 | title: '操作', 32 | align: 'center', 33 | }, 34 | ]; 35 | -------------------------------------------------------------------------------- /src/viewsBusiness/system/constant/post/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | title: '所属租户', 17 | colKey: 'tenantId', 18 | }, 19 | { 20 | title: '岗位类型', 21 | colKey: 'category', 22 | }, 23 | { 24 | title: '岗位编号', 25 | colKey: 'postCode', 26 | }, 27 | { 28 | title: '岗位名称', 29 | colKey: 'postName', 30 | }, 31 | { 32 | title: '岗位排序', 33 | colKey: 'sort', 34 | }, 35 | { 36 | fixed: 'right', 37 | width: 180, 38 | colKey: 'op', 39 | title: '操作', 40 | align: 'center', 41 | }, 42 | ]; 43 | -------------------------------------------------------------------------------- /src/viewsBusiness/system/constant/tenant/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | title: '租户ID', 17 | colKey: 'tenantId', 18 | }, 19 | { 20 | title: '租户名称', 21 | colKey: 'tenantName', 22 | }, 23 | { 24 | title: '联系人', 25 | colKey: 'linkman', 26 | }, 27 | { 28 | title: '联系电话', 29 | colKey: 'contactNumber', 30 | }, 31 | { 32 | title: '账号额度', 33 | colKey: 'accountNumber', 34 | }, 35 | { 36 | title: '过期时间', 37 | colKey: 'expireTime', 38 | }, 39 | { 40 | title: '绑定域名', 41 | colKey: 'domainUrl', 42 | }, 43 | { 44 | fixed: 'right', 45 | width: 180, 46 | colKey: 'op', 47 | title: '操作', 48 | align: 'center', 49 | }, 50 | ]; 51 | -------------------------------------------------------------------------------- /src/viewsBusiness/system/constant/tenant/tenantPackage/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | title: '产品包名', 17 | colKey: 'packageName', 18 | }, 19 | { 20 | title: '备注', 21 | colKey: 'remark', 22 | }, 23 | { 24 | fixed: 'right', 25 | width: 180, 26 | colKey: 'op', 27 | title: '操作', 28 | align: 'center', 29 | }, 30 | ]; 31 | -------------------------------------------------------------------------------- /src/viewsBusiness/system/constant/topmenu/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | colKey: 'name', 17 | title: '菜单名', 18 | }, 19 | { 20 | colKey: 'source', 21 | title: '菜单图标', 22 | }, 23 | { 24 | colKey: 'code', 25 | title: '菜单编号', 26 | }, 27 | { 28 | colKey: 'sort', 29 | title: '菜单排序', 30 | }, 31 | { 32 | fixed: 'right', 33 | width: 180, 34 | colKey: 'op', 35 | title: '操作', 36 | align: 'center', 37 | }, 38 | ]; 39 | -------------------------------------------------------------------------------- /src/viewsBusiness/system/constant/user/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | title: '登录账号', 17 | colKey: 'account', 18 | }, 19 | { 20 | title: '所属租户', 21 | colKey: 'tenantName', 22 | }, 23 | { 24 | title: '用户姓名', 25 | colKey: 'realName', 26 | }, 27 | { 28 | title: '所属角色', 29 | colKey: 'roleName', 30 | }, 31 | { 32 | title: '所属部门', 33 | colKey: 'deptName', 34 | }, 35 | { 36 | title: '用户平台', 37 | colKey: 'userTypeName', 38 | }, 39 | { 40 | fixed: 'right', 41 | width: 180, 42 | colKey: 'op', 43 | title: '操作', 44 | align: 'center', 45 | }, 46 | ]; 47 | -------------------------------------------------------------------------------- /src/viewsBusiness/system/constant/user/platform.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'serial-number', 4 | title: '序号', 5 | width: 80, 6 | align: 'center', 7 | fixed: 'left', 8 | }, 9 | { 10 | title: '登录账号', 11 | colKey: 'account', 12 | }, 13 | { 14 | title: '所属租户', 15 | colKey: 'tenantName', 16 | }, 17 | { 18 | title: '用户姓名', 19 | colKey: 'realName', 20 | }, 21 | { 22 | title: '用户平台', 23 | colKey: 'userTypeName', 24 | }, 25 | { 26 | fixed: 'right', 27 | width: 180, 28 | colKey: 'op', 29 | title: '操作', 30 | align: 'center', 31 | }, 32 | ]; 33 | -------------------------------------------------------------------------------- /src/viewsBusiness/tool/constant/datasource/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'row-select', 4 | type: 'multiple', 5 | width: 64, 6 | fixed: 'left', 7 | }, 8 | { 9 | colKey: 'serial-number', 10 | title: '序号', 11 | width: 80, 12 | align: 'center', 13 | fixed: 'left', 14 | }, 15 | { 16 | title: '名称', 17 | colKey: 'name', 18 | }, 19 | { 20 | title: '驱动类', 21 | colKey: 'driverClass', 22 | }, 23 | { 24 | title: '用户名', 25 | colKey: 'username', 26 | }, 27 | { 28 | title: '连接地址', 29 | colKey: 'url', 30 | }, 31 | { 32 | fixed: 'right', 33 | width: 180, 34 | colKey: 'op', 35 | title: '操作', 36 | align: 'center', 37 | }, 38 | ]; 39 | 40 | export const DRIVER_CLASS = [ 41 | { 42 | dictKey: 'com.mysql.cj.jdbc.Driver', 43 | dictValue: 'com.mysql.cj.jdbc.Driver', 44 | }, 45 | { 46 | dictKey: 'org.postgresql.Driver', 47 | dictValue: 'org.postgresql.Driver', 48 | }, 49 | { 50 | dictKey: 'oracle.jdbc.OracleDriver', 51 | dictValue: 'oracle.jdbc.OracleDriver', 52 | }, 53 | { 54 | dictKey: 'com.microsoft.sqlserver.jdbc.SQLServerDriver', 55 | dictValue: 'com.microsoft.sqlserver.jdbc.SQLServerDriver', 56 | }, 57 | { 58 | dictKey: 'dm.jdbc.driver.DmDriver', 59 | dictValue: 'dm.jdbc.driver.DmDriver', 60 | }, 61 | ]; 62 | -------------------------------------------------------------------------------- /src/viewsBusiness/work/constant/claim/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'serial-number', 4 | title: '序号', 5 | width: 80, 6 | align: 'center', 7 | fixed: 'left', 8 | }, 9 | { 10 | title: '流程分类', 11 | colKey: 'categoryName', 12 | }, 13 | { 14 | title: '流程名称', 15 | colKey: 'processDefinitionName', 16 | }, 17 | { 18 | title: '当前步骤', 19 | colKey: 'taskName', 20 | }, 21 | { 22 | title: '流程版本', 23 | colKey: 'processDefinitionVersion', 24 | }, 25 | { 26 | title: '申请时间', 27 | colKey: 'createTime', 28 | }, 29 | { 30 | fixed: 'right', 31 | width: 200, 32 | colKey: 'op', 33 | title: '操作', 34 | align: 'center', 35 | }, 36 | ]; 37 | -------------------------------------------------------------------------------- /src/viewsBusiness/work/constant/done/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'serial-number', 4 | title: '序号', 5 | width: 80, 6 | align: 'center', 7 | fixed: 'left', 8 | }, 9 | { 10 | title: '流程分类', 11 | colKey: 'categoryName', 12 | }, 13 | { 14 | title: '流程名称', 15 | colKey: 'processDefinitionName', 16 | }, 17 | { 18 | title: '当前步骤', 19 | colKey: 'taskName', 20 | }, 21 | { 22 | title: '流程版本', 23 | colKey: 'processDefinitionVersion', 24 | }, 25 | { 26 | title: '申请时间', 27 | colKey: 'createTime', 28 | }, 29 | { 30 | fixed: 'right', 31 | width: 180, 32 | colKey: 'op', 33 | title: '操作', 34 | align: 'center', 35 | }, 36 | ]; 37 | -------------------------------------------------------------------------------- /src/viewsBusiness/work/constant/send/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'serial-number', 4 | title: '序号', 5 | width: 80, 6 | align: 'center', 7 | fixed: 'left', 8 | }, 9 | { 10 | title: '流程分类', 11 | colKey: 'categoryName', 12 | }, 13 | { 14 | title: '流程名称', 15 | colKey: 'processDefinitionName', 16 | }, 17 | { 18 | title: '当前步骤', 19 | colKey: 'taskName', 20 | }, 21 | { 22 | title: '流程版本', 23 | colKey: 'processDefinitionVersion', 24 | }, 25 | { 26 | title: '流程进度', 27 | colKey: 'processIsFinished', 28 | }, 29 | { 30 | title: '申请时间', 31 | colKey: 'createTime', 32 | }, 33 | { 34 | fixed: 'right', 35 | width: 180, 36 | colKey: 'op', 37 | title: '操作', 38 | align: 'center', 39 | }, 40 | ]; 41 | -------------------------------------------------------------------------------- /src/viewsBusiness/work/constant/start/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'serial-number', 4 | title: '序号', 5 | width: 80, 6 | align: 'center', 7 | fixed: 'left', 8 | }, 9 | { 10 | title: '租户编号', 11 | colKey: 'tenantId', 12 | }, 13 | { 14 | title: '流程分类', 15 | colKey: 'categoryName', 16 | }, 17 | { 18 | title: '流程标识', 19 | colKey: 'key', 20 | }, 21 | { 22 | title: '流程名称', 23 | colKey: 'name', 24 | }, 25 | { 26 | title: '流程版本', 27 | colKey: 'version', 28 | }, 29 | { 30 | title: '状态', 31 | colKey: 'suspensionState', 32 | }, 33 | { 34 | title: '部署时间', 35 | colKey: 'deploymentTime', 36 | }, 37 | { 38 | fixed: 'right', 39 | width: 210, 40 | colKey: 'op', 41 | title: '操作', 42 | align: 'center', 43 | }, 44 | ]; 45 | -------------------------------------------------------------------------------- /src/viewsBusiness/work/constant/todo/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLUMNS = [ 2 | { 3 | colKey: 'serial-number', 4 | title: '序号', 5 | width: 80, 6 | align: 'center', 7 | fixed: 'left', 8 | }, 9 | { 10 | title: '流程分类', 11 | colKey: 'categoryName', 12 | }, 13 | { 14 | title: '流程名称', 15 | colKey: 'processDefinitionName', 16 | }, 17 | { 18 | title: '当前步骤', 19 | colKey: 'taskName', 20 | }, 21 | { 22 | title: '流程版本', 23 | colKey: 'processDefinitionVersion', 24 | }, 25 | { 26 | title: '申请时间', 27 | colKey: 'createTime', 28 | }, 29 | { 30 | fixed: 'right', 31 | width: 200, 32 | colKey: 'op', 33 | title: '操作', 34 | align: 'center', 35 | }, 36 | ]; 37 | -------------------------------------------------------------------------------- /stylelint.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | defaultSeverity: 'error', 3 | extends: ['stylelint-config-standard'], 4 | rules: { 5 | 'no-descending-specificity': null, 6 | 'import-notation': 'string', 7 | 'no-empty-source': null, 8 | 'custom-property-pattern': null, 9 | 'selector-class-pattern': null, 10 | 'selector-pseudo-class-no-unknown': [ 11 | true, 12 | { 13 | ignorePseudoClasses: ['deep'], 14 | }, 15 | ], 16 | 'media-query-no-invalid': null, // 官方表示此规则应当仅对于原生CSS启用,对于预处理器(Less)不应启用 17 | }, 18 | overrides: [ 19 | { 20 | files: ['**/*.html', '**/*.vue'], 21 | customSyntax: 'postcss-html', 22 | }, 23 | { 24 | files: ['**/*.less'], 25 | customSyntax: 'postcss-less', 26 | }, 27 | ], 28 | }; 29 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "jsx": "preserve", 7 | "sourceMap": true, 8 | "resolveJsonModule": true, 9 | "esModuleInterop": true, 10 | "skipLibCheck": true, 11 | "allowSyntheticDefaultImports": true, 12 | "lib": ["esnext", "dom"], 13 | "types": ["vite/client"], 14 | "noEmit": true, 15 | "baseUrl": "./", 16 | "paths": { 17 | "@/*": ["src/*"] 18 | }, 19 | "noImplicitAny": true 20 | }, 21 | "include": [ 22 | "**/*.ts", 23 | "src/**/*.d.ts", 24 | "src/types/**/*.d.ts", 25 | "src/**/*.ts", 26 | "src/**/*.tsx", 27 | "src/**/*.vue", 28 | "node_modules/tdesign-vue-next/global.d.ts" 29 | ], 30 | "compileOnSave": false 31 | } 32 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import createVuePlugin from '@vitejs/plugin-vue'; 2 | import vueJsx from '@vitejs/plugin-vue-jsx'; 3 | import path from 'path'; 4 | import { type ConfigEnv, loadEnv, type UserConfig } from 'vite'; 5 | import svgLoader from 'vite-svg-loader'; 6 | 7 | import { createMock } from './build/vite/mock'; 8 | import { createProxy } from './build/vite/proxy'; 9 | import { prefix } from './src/config/global'; 10 | import proxyConfig from './src/config/proxy'; 11 | 12 | const CWD = process.cwd(); 13 | 14 | // https://vitejs.dev/config/ 15 | export default ({ command, mode }: ConfigEnv): UserConfig => { 16 | const { VITE_BASE_URL } = loadEnv(mode, CWD); 17 | return { 18 | base: VITE_BASE_URL, 19 | resolve: { 20 | alias: { 21 | '@': path.resolve(__dirname, './src'), 22 | }, 23 | }, 24 | css: { 25 | preprocessorOptions: { 26 | less: { 27 | modifyVars: { 28 | hack: `true; @import (reference) "${path.resolve('src/style/variables.less')}";`, 29 | // 全局公共前缀 30 | '@starter-prefix': prefix, 31 | }, 32 | math: 'strict', 33 | javascriptEnabled: true, 34 | }, 35 | }, 36 | }, 37 | plugins: [createVuePlugin(), vueJsx(), createMock(command, mode), svgLoader()], 38 | 39 | server: { 40 | port: 3002, 41 | host: '0.0.0.0', 42 | // mock则不配置vite代理 43 | ...(mode !== 'mock' ? { proxy: createProxy(proxyConfig[mode].proxy) } : {}), 44 | }, 45 | }; 46 | }; 47 | --------------------------------------------------------------------------------