Showing
48 changed files
with
2994 additions
and
87 deletions
.env.development
0 → 100644
.env.production
0 → 100644
| 1 | 1 | import path from 'path' |
| 2 | +import { BuildOptions } from 'vite' | |
| 2 | 3 | export const OUTPUT_DIR = 'dist' |
| 3 | 4 | |
| 4 | 5 | // monaco-editor 路径 |
| ... | ... | @@ -11,12 +12,12 @@ export const chunkSizeWarningLimit = 2000 |
| 11 | 12 | export const brotliSize = false |
| 12 | 13 | |
| 13 | 14 | // 分包 |
| 14 | -export const rollupOptions = { | |
| 15 | +export const rollupOptions: BuildOptions['rollupOptions'] = { | |
| 15 | 16 | output: { |
| 16 | 17 | chunkFileNames: 'static/js/[name]-[hash].js', |
| 17 | 18 | entryFileNames: 'static/js/[name]-[hash].js', |
| 18 | 19 | assetFileNames: (chunkInfo) => { |
| 19 | - if(['.png', '.jpg', '.jpeg'].includes(path.extname(chunkInfo.name))) { | |
| 20 | + if (['.png', '.jpg', '.jpeg'].includes(path.extname(chunkInfo.name!))) { | |
| 20 | 21 | return `static/[ext]/[name].[ext]` |
| 21 | 22 | } |
| 22 | 23 | return `static/[ext]/[name]-[hash].[ext]` | ... | ... |
build/external/globConfig/const.ts
0 → 100644
build/external/globConfig/getGlobConfigName.ts
renamed from
build/getConfigFileName.ts
| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | * Get the configuration file variable name |
| 3 | 3 | * @param env |
| 4 | 4 | */ |
| 5 | -export const getConfigFileName = (env: Record<string, any>) => { | |
| 5 | +export const getGlobalConfigName = (env: Record<string, any>) => { | |
| 6 | 6 | return `__PRODUCTION__${env.VITE_GLOB_APP_SHORT_NAME || '__APP'}__CONF__` |
| 7 | 7 | .toUpperCase() |
| 8 | 8 | .replace(/\s/g, ''); | ... | ... |
build/external/globConfig/index.ts
0 → 100644
| 1 | +import { getRootPath } from "../utils"; | |
| 2 | +import { writeFileSync } from "fs"; | |
| 3 | +import { Plugin } from "vite"; | |
| 4 | +import { GLOB_CONFIG_FILE_NAME } from "./const"; | |
| 5 | +import { getGlobalConfigName } from "./getGlobConfigName"; | |
| 6 | + | |
| 7 | +export function GenerateBuildConfig(viteEnv: Record<string, any>) { | |
| 8 | + return { | |
| 9 | + name: 'vite-plugin-generate-global-config', | |
| 10 | + apply: 'build', | |
| 11 | + enforce: 'post', | |
| 12 | + closeBundle() { | |
| 13 | + | |
| 14 | + function createConfig({ config, configName, configFileName }: { configName: string, config: Record<string, any>, configFileName?: string } = { configName: '', config: {} }) { | |
| 15 | + try { | |
| 16 | + const windowConf = `window.${configName}`; | |
| 17 | + // Ensure that the variable will not be modified | |
| 18 | + const configStr = `${windowConf}=${JSON.stringify(config)}; | |
| 19 | + Object.freeze(${windowConf}); | |
| 20 | + Object.defineProperty(window, "${configName}", { | |
| 21 | + configurable: false, | |
| 22 | + writable: false, | |
| 23 | + }); | |
| 24 | + `.replace(/\s/g, ''); | |
| 25 | + | |
| 26 | + writeFileSync(getRootPath(`dist/${configFileName}`), configStr, { encoding: 'utf-8' }) | |
| 27 | + } catch (error) { | |
| 28 | + | |
| 29 | + } | |
| 30 | + } | |
| 31 | + | |
| 32 | + const configName = getGlobalConfigName(viteEnv as ImportMetaEnv) | |
| 33 | + | |
| 34 | + createConfig({ config: viteEnv, configFileName: GLOB_CONFIG_FILE_NAME, configName }) | |
| 35 | + | |
| 36 | + } | |
| 37 | + } as Plugin | |
| 38 | +} | |
| 39 | + | ... | ... |
build/external/globConfig/useGlobSetting.ts
0 → 100644
| 1 | +import { getGlobalConfigName } from "./getGlobConfigName"; | |
| 2 | + | |
| 3 | + | |
| 4 | +export function getAppEnvConfig() { | |
| 5 | + const ENV_NAME = getGlobalConfigName(import.meta.env); | |
| 6 | + | |
| 7 | + const ENV = (import.meta.env.DEV | |
| 8 | + ? // Get the global configuration (the configuration will be extracted independently when packaging) | |
| 9 | + (import.meta.env as unknown as GlobEnvConfig) | |
| 10 | + : window[ENV_NAME as any]) as unknown as GlobEnvConfig; | |
| 11 | + const { | |
| 12 | + VITE_GLOB_APP_TITLE, | |
| 13 | + VITE_GLOB_APP_SHORT_NAME, | |
| 14 | + VITE_GLOB_CONTENT_SECURITY_POLICY, | |
| 15 | + } = ENV; | |
| 16 | + | |
| 17 | + if (!/^[a-zA-Z\_]*$/.test(VITE_GLOB_APP_SHORT_NAME)) { | |
| 18 | + console.warn( | |
| 19 | + `VITE_GLOB_APP_SHORT_NAME Variables can only be characters/underscores, please modify in the environment variables and re-running.` | |
| 20 | + ); | |
| 21 | + } | |
| 22 | + | |
| 23 | + return { | |
| 24 | + VITE_GLOB_APP_TITLE, | |
| 25 | + VITE_GLOB_APP_SHORT_NAME, | |
| 26 | + VITE_GLOB_CONTENT_SECURITY_POLICY, | |
| 27 | + }; | |
| 28 | +} | |
| 29 | + | |
| 30 | +export const useGlobSetting = (): Readonly<GlobConfig> => { | |
| 31 | + const { | |
| 32 | + VITE_GLOB_APP_TITLE, | |
| 33 | + VITE_GLOB_APP_SHORT_NAME, | |
| 34 | + VITE_GLOB_CONTENT_SECURITY_POLICY, | |
| 35 | + } = getAppEnvConfig(); | |
| 36 | + | |
| 37 | + if (!/[a-zA-Z\_]*/.test(VITE_GLOB_APP_SHORT_NAME)) { | |
| 38 | + console.warn( | |
| 39 | + `VITE_GLOB_APP_SHORT_NAME Variables can only be characters/underscores, please modify in the environment variables and re-running.` | |
| 40 | + ); | |
| 41 | + } | |
| 42 | + | |
| 43 | + // Take global configuration | |
| 44 | + const glob: Readonly<GlobConfig> = { | |
| 45 | + title: VITE_GLOB_APP_TITLE, | |
| 46 | + securityPolicy: VITE_GLOB_CONTENT_SECURITY_POLICY, | |
| 47 | + }; | |
| 48 | + | |
| 49 | + return glob as Readonly<GlobConfig>; | |
| 50 | +}; | ... | ... |
build/external/utils.ts
0 → 100644
| 1 | +import { resolve } from "path" | |
| 2 | + | |
| 3 | +export function parseEnv(env: ImportMetaEnv) { | |
| 4 | + const res: Record<string, any> = {} | |
| 5 | + | |
| 6 | + for (const envName of Object.keys(env)) { | |
| 7 | + let value = env[envName] | |
| 8 | + | |
| 9 | + // parese to boolean | |
| 10 | + value = value === 'true' ? true : value === 'false' ? false : value | |
| 11 | + | |
| 12 | + if (envName === 'VITE_GLOB_PROXY') { | |
| 13 | + try { | |
| 14 | + value = JSON.parse(value) | |
| 15 | + } catch (error) { | |
| 16 | + value = '' | |
| 17 | + } | |
| 18 | + } | |
| 19 | + | |
| 20 | + res[envName] = value | |
| 21 | + | |
| 22 | + if (typeof value === 'string') { | |
| 23 | + process.env[envName] = value | |
| 24 | + } else if (typeof value === 'object') { | |
| 25 | + process.env[envName] === JSON.stringify(value) | |
| 26 | + } | |
| 27 | + | |
| 28 | + } | |
| 29 | + | |
| 30 | + return res | |
| 31 | +} | |
| 32 | + | |
| 33 | +export function getEnvConfig(match = 'VITE_GLOB_',) { | |
| 34 | + | |
| 35 | +} | |
| 36 | + | |
| 37 | +export function getRootPath(...dir: string[]) { | |
| 38 | + return resolve(process.cwd(), ...dir); | |
| 39 | +} | ... | ... |
build/external/vite/html.ts
0 → 100644
| 1 | +import { createHtmlPlugin } from 'vite-plugin-html' | |
| 2 | + | |
| 3 | +const GLOB_CONFIG_FILE_NAME = '_app.config.js' | |
| 4 | + | |
| 5 | +export function configHtmlPlugin(env: ImportMetaEnv, isBuild: boolean) { | |
| 6 | + const { VITE_GLOB_APP_TITLE, VITE_GLOB_CONTENT_SECURITY_POLICY, VITE_GLOB_PUBLIC_PATH } = env | |
| 7 | + const getAppConfigSrc = () => { | |
| 8 | + const path = VITE_GLOB_PUBLIC_PATH.endsWith('/') ? VITE_GLOB_PUBLIC_PATH : `${VITE_GLOB_PUBLIC_PATH}` | |
| 9 | + return `${path || '/'}${GLOB_CONFIG_FILE_NAME}?v=${Date.now()}` | |
| 10 | + } | |
| 11 | + | |
| 12 | + const htmlPlugin = createHtmlPlugin({ | |
| 13 | + minify: isBuild, | |
| 14 | + inject: { | |
| 15 | + data: { | |
| 16 | + title: VITE_GLOB_APP_TITLE, | |
| 17 | + contentSecurityPolicy: VITE_GLOB_CONTENT_SECURITY_POLICY ? `<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" />` : '' | |
| 18 | + }, | |
| 19 | + tags: isBuild ? [ | |
| 20 | + { | |
| 21 | + tag: 'script', | |
| 22 | + attrs: { src: getAppConfigSrc() } | |
| 23 | + } | |
| 24 | + ] : [] | |
| 25 | + } | |
| 26 | + }) | |
| 27 | + | |
| 28 | + return htmlPlugin | |
| 29 | +} | ... | ... |
build/external/vite/proxy.ts
0 → 100644
| 1 | +import { ProxyOptions } from "vite" | |
| 2 | + | |
| 3 | +export const createProxy = (viteEnv: ImportMetaEnv) => { | |
| 4 | + const { VITE_GLOB_PROXY } = viteEnv | |
| 5 | + const httpsReg = /^https:\/\//; | |
| 6 | + const res: Record<string, ProxyOptions> = {} | |
| 7 | + | |
| 8 | + for (const [prefix, target] of VITE_GLOB_PROXY) { | |
| 9 | + const isHttps = httpsReg.test(prefix) | |
| 10 | + | |
| 11 | + res[prefix] = { | |
| 12 | + target, | |
| 13 | + changeOrigin: true, | |
| 14 | + ws: true, | |
| 15 | + rewrite: (path) => path.replace(new RegExp(`^${prefix}`), ''), | |
| 16 | + ...(isHttps ? { secure: false } : {}) | |
| 17 | + } | |
| 18 | + } | |
| 19 | + | |
| 20 | + return res | |
| 21 | +} | ... | ... |
| ... | ... | @@ -31,10 +31,12 @@ |
| 31 | 31 | "gsap": "^3.11.3", |
| 32 | 32 | "highlight.js": "^11.5.0", |
| 33 | 33 | "html2canvas": "^1.4.1", |
| 34 | + "jwt-decode": "^3.1.2", | |
| 34 | 35 | "keymaster": "^1.6.2", |
| 35 | 36 | "monaco-editor": "^0.33.0", |
| 36 | 37 | "naive-ui": "2.34.3", |
| 37 | 38 | "pinia": "^2.0.13", |
| 39 | + "qs": "^6.11.0", | |
| 38 | 40 | "screenfull": "^6.0.1", |
| 39 | 41 | "three": "^0.145.0", |
| 40 | 42 | "vue": "^3.2.31", |
| ... | ... | @@ -49,6 +51,7 @@ |
| 49 | 51 | "@commitlint/cli": "^17.0.2", |
| 50 | 52 | "@commitlint/config-conventional": "^17.0.2", |
| 51 | 53 | "@types/node": "^16.11.26", |
| 54 | + "@types/qs": "^6.9.7", | |
| 52 | 55 | "@types/three": "^0.144.0", |
| 53 | 56 | "@typescript-eslint/eslint-plugin": "^5.18.0", |
| 54 | 57 | "@typescript-eslint/parser": "^5.18.0", |
| ... | ... | @@ -76,6 +79,7 @@ |
| 76 | 79 | "typescript": "4.6.3", |
| 77 | 80 | "vite": "2.9.9", |
| 78 | 81 | "vite-plugin-compression": "^0.5.1", |
| 82 | + "vite-plugin-html": "^3.2.0", | |
| 79 | 83 | "vite-plugin-importer": "^0.2.5", |
| 80 | 84 | "vite-plugin-mock": "^2.9.6", |
| 81 | 85 | "vite-plugin-monaco-editor": "^1.1.0", | ... | ... |
| ... | ... | @@ -10,6 +10,7 @@ specifiers: |
| 10 | 10 | '@types/keymaster': ^1.6.30 |
| 11 | 11 | '@types/lodash': ^4.14.184 |
| 12 | 12 | '@types/node': ^16.11.26 |
| 13 | + '@types/qs': ^6.9.7 | |
| 13 | 14 | '@types/three': ^0.144.0 |
| 14 | 15 | '@typescript-eslint/eslint-plugin': ^5.18.0 |
| 15 | 16 | '@typescript-eslint/parser': ^5.18.0 |
| ... | ... | @@ -39,6 +40,7 @@ specifiers: |
| 39 | 40 | highlight.js: ^11.5.0 |
| 40 | 41 | html2canvas: ^1.4.1 |
| 41 | 42 | husky: ^8.0.1 |
| 43 | + jwt-decode: ^3.1.2 | |
| 42 | 44 | keymaster: ^1.6.2 |
| 43 | 45 | lodash: ~4.17.21 |
| 44 | 46 | mockjs: ^1.1.0 |
| ... | ... | @@ -47,6 +49,7 @@ specifiers: |
| 47 | 49 | pinia: ^2.0.13 |
| 48 | 50 | plop: ^3.0.5 |
| 49 | 51 | prettier: ^2.6.2 |
| 52 | + qs: ^6.11.0 | |
| 50 | 53 | sass: ^1.49.11 |
| 51 | 54 | sass-loader: ^12.6.0 |
| 52 | 55 | screenfull: ^6.0.1 |
| ... | ... | @@ -54,6 +57,7 @@ specifiers: |
| 54 | 57 | typescript: 4.6.3 |
| 55 | 58 | vite: 2.9.9 |
| 56 | 59 | vite-plugin-compression: ^0.5.1 |
| 60 | + vite-plugin-html: ^3.2.0 | |
| 57 | 61 | vite-plugin-importer: ^0.2.5 |
| 58 | 62 | vite-plugin-mock: ^2.9.6 |
| 59 | 63 | vite-plugin-monaco-editor: ^1.1.0 |
| ... | ... | @@ -85,10 +89,12 @@ dependencies: |
| 85 | 89 | gsap: 3.11.3 |
| 86 | 90 | highlight.js: 11.5.1 |
| 87 | 91 | html2canvas: 1.4.1 |
| 92 | + jwt-decode: 3.1.2 | |
| 88 | 93 | keymaster: 1.6.2 |
| 89 | 94 | monaco-editor: 0.33.0 |
| 90 | 95 | naive-ui: 2.34.3_vue@3.2.37 |
| 91 | 96 | pinia: 2.0.14_ub5l46u3nefphax5x2tezui4oq |
| 97 | + qs: 6.11.0 | |
| 92 | 98 | screenfull: 6.0.1 |
| 93 | 99 | three: 0.145.0 |
| 94 | 100 | vue: 3.2.37 |
| ... | ... | @@ -103,6 +109,7 @@ devDependencies: |
| 103 | 109 | '@commitlint/cli': 17.0.2 |
| 104 | 110 | '@commitlint/config-conventional': 17.0.2 |
| 105 | 111 | '@types/node': 16.11.40 |
| 112 | + '@types/qs': 6.9.7 | |
| 106 | 113 | '@types/three': 0.144.0 |
| 107 | 114 | '@typescript-eslint/eslint-plugin': 5.28.0_evi7yu7wunhzwb24olrfvzynny |
| 108 | 115 | '@typescript-eslint/parser': 5.28.0_sfmgizikprcxt7r54j7cnzjamu |
| ... | ... | @@ -130,6 +137,7 @@ devDependencies: |
| 130 | 137 | typescript: 4.6.3 |
| 131 | 138 | vite: 2.9.9_sass@1.52.3 |
| 132 | 139 | vite-plugin-compression: 0.5.1_vite@2.9.9 |
| 140 | + vite-plugin-html: 3.2.0_vite@2.9.9 | |
| 133 | 141 | vite-plugin-importer: 0.2.5 |
| 134 | 142 | vite-plugin-mock: 2.9.6_mockjs@1.1.0+vite@2.9.9 |
| 135 | 143 | vite-plugin-monaco-editor: 1.1.0_monaco-editor@0.33.0 |
| ... | ... | @@ -745,6 +753,13 @@ packages: |
| 745 | 753 | engines: {node: '>=6.0.0'} |
| 746 | 754 | dev: true |
| 747 | 755 | |
| 756 | + /@jridgewell/source-map/0.3.2: | |
| 757 | + resolution: {integrity: sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==} | |
| 758 | + dependencies: | |
| 759 | + '@jridgewell/gen-mapping': 0.3.1 | |
| 760 | + '@jridgewell/trace-mapping': 0.3.13 | |
| 761 | + dev: true | |
| 762 | + | |
| 748 | 763 | /@jridgewell/sourcemap-codec/1.4.13: |
| 749 | 764 | resolution: {integrity: sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==} |
| 750 | 765 | dev: true |
| ... | ... | @@ -928,6 +943,10 @@ packages: |
| 928 | 943 | resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} |
| 929 | 944 | dev: true |
| 930 | 945 | |
| 946 | + /@types/qs/6.9.7: | |
| 947 | + resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==} | |
| 948 | + dev: true | |
| 949 | + | |
| 931 | 950 | /@types/resolve/1.17.1: |
| 932 | 951 | resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} |
| 933 | 952 | dependencies: |
| ... | ... | @@ -1237,7 +1256,6 @@ packages: |
| 1237 | 1256 | dependencies: |
| 1238 | 1257 | '@vue/reactivity': 3.2.37 |
| 1239 | 1258 | '@vue/shared': 3.2.37 |
| 1240 | - dev: false | |
| 1241 | 1259 | |
| 1242 | 1260 | /@vue/runtime-dom/3.2.37: |
| 1243 | 1261 | resolution: {integrity: sha512-HimKdh9BepShW6YozwRKAYjYQWg9mQn63RGEiSswMbW+ssIht1MILYlVGkAGGQbkhSh31PCdoUcfiu4apXJoPw==} |
| ... | ... | @@ -1245,7 +1263,6 @@ packages: |
| 1245 | 1263 | '@vue/runtime-core': 3.2.37 |
| 1246 | 1264 | '@vue/shared': 3.2.37 |
| 1247 | 1265 | csstype: 2.6.20 |
| 1248 | - dev: false | |
| 1249 | 1266 | |
| 1250 | 1267 | /@vue/server-renderer/3.2.37_vue@3.2.37: |
| 1251 | 1268 | resolution: {integrity: sha512-kLITEJvaYgZQ2h47hIzPh2K3jG8c1zCVbp/o/bzQOyvzaKiCquKS7AaioPI28GNxIsE/zSx+EwWYsNxDCX95MA==} |
| ... | ... | @@ -1255,7 +1272,6 @@ packages: |
| 1255 | 1272 | '@vue/compiler-ssr': 3.2.37 |
| 1256 | 1273 | '@vue/shared': 3.2.37 |
| 1257 | 1274 | vue: 3.2.37 |
| 1258 | - dev: false | |
| 1259 | 1275 | |
| 1260 | 1276 | /@vue/shared/3.2.37: |
| 1261 | 1277 | resolution: {integrity: sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw==} |
| ... | ... | @@ -1449,6 +1465,10 @@ packages: |
| 1449 | 1465 | resolution: {integrity: sha512-p4DO/JXwjs8klJyJL8Q2oM4ks5fUTze/h5k10oPPKMiLe1fj3G1QMzPHNmN1Py4ycOk7WlO2DcGXv1qiESJCZA==} |
| 1450 | 1466 | dev: false |
| 1451 | 1467 | |
| 1468 | + /async/3.2.4: | |
| 1469 | + resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} | |
| 1470 | + dev: true | |
| 1471 | + | |
| 1452 | 1472 | /asynckit/0.4.0: |
| 1453 | 1473 | resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} |
| 1454 | 1474 | dev: false |
| ... | ... | @@ -1520,6 +1540,12 @@ packages: |
| 1520 | 1540 | concat-map: 0.0.1 |
| 1521 | 1541 | dev: true |
| 1522 | 1542 | |
| 1543 | + /brace-expansion/2.0.1: | |
| 1544 | + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} | |
| 1545 | + dependencies: | |
| 1546 | + balanced-match: 1.0.2 | |
| 1547 | + dev: true | |
| 1548 | + | |
| 1523 | 1549 | /braces/3.0.2: |
| 1524 | 1550 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} |
| 1525 | 1551 | engines: {node: '>=8'} |
| ... | ... | @@ -1539,6 +1565,10 @@ packages: |
| 1539 | 1565 | picocolors: 1.0.0 |
| 1540 | 1566 | dev: true |
| 1541 | 1567 | |
| 1568 | + /buffer-from/1.1.2: | |
| 1569 | + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} | |
| 1570 | + dev: true | |
| 1571 | + | |
| 1542 | 1572 | /buffer/5.7.1: |
| 1543 | 1573 | resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} |
| 1544 | 1574 | dependencies: |
| ... | ... | @@ -1563,7 +1593,6 @@ packages: |
| 1563 | 1593 | dependencies: |
| 1564 | 1594 | function-bind: 1.1.1 |
| 1565 | 1595 | get-intrinsic: 1.1.2 |
| 1566 | - dev: true | |
| 1567 | 1596 | |
| 1568 | 1597 | /callsites/3.1.0: |
| 1569 | 1598 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} |
| ... | ... | @@ -1672,6 +1701,13 @@ packages: |
| 1672 | 1701 | fsevents: 2.3.2 |
| 1673 | 1702 | dev: true |
| 1674 | 1703 | |
| 1704 | + /clean-css/5.3.2: | |
| 1705 | + resolution: {integrity: sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==} | |
| 1706 | + engines: {node: '>= 10.0'} | |
| 1707 | + dependencies: | |
| 1708 | + source-map: 0.6.1 | |
| 1709 | + dev: true | |
| 1710 | + | |
| 1675 | 1711 | /clean-stack/2.2.0: |
| 1676 | 1712 | resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} |
| 1677 | 1713 | engines: {node: '>=6'} |
| ... | ... | @@ -1748,6 +1784,10 @@ packages: |
| 1748 | 1784 | color-string: 1.9.1 |
| 1749 | 1785 | dev: false |
| 1750 | 1786 | |
| 1787 | + /colorette/2.0.19: | |
| 1788 | + resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==} | |
| 1789 | + dev: true | |
| 1790 | + | |
| 1751 | 1791 | /combined-stream/1.0.8: |
| 1752 | 1792 | resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} |
| 1753 | 1793 | engines: {node: '>= 0.8'} |
| ... | ... | @@ -1755,6 +1795,15 @@ packages: |
| 1755 | 1795 | delayed-stream: 1.0.0 |
| 1756 | 1796 | dev: false |
| 1757 | 1797 | |
| 1798 | + /commander/2.20.3: | |
| 1799 | + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} | |
| 1800 | + dev: true | |
| 1801 | + | |
| 1802 | + /commander/8.3.0: | |
| 1803 | + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} | |
| 1804 | + engines: {node: '>= 12'} | |
| 1805 | + dev: true | |
| 1806 | + | |
| 1758 | 1807 | /commander/9.3.0: |
| 1759 | 1808 | resolution: {integrity: sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==} |
| 1760 | 1809 | engines: {node: ^12.20.0 || >=14} |
| ... | ... | @@ -1783,6 +1832,11 @@ packages: |
| 1783 | 1832 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} |
| 1784 | 1833 | dev: true |
| 1785 | 1834 | |
| 1835 | + /connect-history-api-fallback/1.6.0: | |
| 1836 | + resolution: {integrity: sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==} | |
| 1837 | + engines: {node: '>=0.8'} | |
| 1838 | + dev: true | |
| 1839 | + | |
| 1786 | 1840 | /connect/3.7.0: |
| 1787 | 1841 | resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} |
| 1788 | 1842 | engines: {node: '>= 0.10.0'} |
| ... | ... | @@ -1795,6 +1849,10 @@ packages: |
| 1795 | 1849 | - supports-color |
| 1796 | 1850 | dev: true |
| 1797 | 1851 | |
| 1852 | + /consola/2.15.3: | |
| 1853 | + resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==} | |
| 1854 | + dev: true | |
| 1855 | + | |
| 1798 | 1856 | /constant-case/3.0.4: |
| 1799 | 1857 | resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} |
| 1800 | 1858 | dependencies: |
| ... | ... | @@ -1832,8 +1890,8 @@ packages: |
| 1832 | 1890 | engines: {node: '>=10'} |
| 1833 | 1891 | hasBin: true |
| 1834 | 1892 | dependencies: |
| 1835 | - is-text-path: 1.0.1 | |
| 1836 | 1893 | JSONStream: 1.3.5 |
| 1894 | + is-text-path: 1.0.1 | |
| 1837 | 1895 | lodash: 4.17.21 |
| 1838 | 1896 | meow: 8.1.2 |
| 1839 | 1897 | split2: 3.2.2 |
| ... | ... | @@ -1904,6 +1962,21 @@ packages: |
| 1904 | 1962 | csstype: 3.0.11 |
| 1905 | 1963 | dev: false |
| 1906 | 1964 | |
| 1965 | + /css-select/4.3.0: | |
| 1966 | + resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} | |
| 1967 | + dependencies: | |
| 1968 | + boolbase: 1.0.0 | |
| 1969 | + css-what: 6.1.0 | |
| 1970 | + domhandler: 4.3.1 | |
| 1971 | + domutils: 2.8.0 | |
| 1972 | + nth-check: 2.1.1 | |
| 1973 | + dev: true | |
| 1974 | + | |
| 1975 | + /css-what/6.1.0: | |
| 1976 | + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} | |
| 1977 | + engines: {node: '>= 6'} | |
| 1978 | + dev: true | |
| 1979 | + | |
| 1907 | 1980 | /cssesc/3.0.0: |
| 1908 | 1981 | resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} |
| 1909 | 1982 | engines: {node: '>=4'} |
| ... | ... | @@ -1912,7 +1985,6 @@ packages: |
| 1912 | 1985 | |
| 1913 | 1986 | /csstype/2.6.20: |
| 1914 | 1987 | resolution: {integrity: sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==} |
| 1915 | - dev: false | |
| 1916 | 1988 | |
| 1917 | 1989 | /csstype/3.0.11: |
| 1918 | 1990 | resolution: {integrity: sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==} |
| ... | ... | @@ -2112,6 +2184,16 @@ packages: |
| 2112 | 2184 | is-obj: 2.0.0 |
| 2113 | 2185 | dev: true |
| 2114 | 2186 | |
| 2187 | + /dotenv-expand/8.0.3: | |
| 2188 | + resolution: {integrity: sha512-SErOMvge0ZUyWd5B0NXMQlDkN+8r+HhVUsxgOO7IoPDOdDRD2JjExpN6y3KnFR66jsJMwSn1pqIivhU5rcJiNg==} | |
| 2189 | + engines: {node: '>=12'} | |
| 2190 | + dev: true | |
| 2191 | + | |
| 2192 | + /dotenv/16.0.3: | |
| 2193 | + resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} | |
| 2194 | + engines: {node: '>=12'} | |
| 2195 | + dev: true | |
| 2196 | + | |
| 2115 | 2197 | /echarts-liquidfill/3.1.0_echarts@5.3.3: |
| 2116 | 2198 | resolution: {integrity: sha512-5Dlqs/jTsdTUAsd+K5LPLLTgrbbNORUSBQyk8PSy1Mg2zgHDWm83FmvA4s0ooNepCJojFYRITTQ4GU1UUSKYLw==} |
| 2117 | 2199 | peerDependencies: |
| ... | ... | @@ -2137,12 +2219,19 @@ packages: |
| 2137 | 2219 | dependencies: |
| 2138 | 2220 | tslib: 2.3.0 |
| 2139 | 2221 | zrender: 5.3.2 |
| 2140 | - dev: true | |
| 2141 | 2222 | |
| 2142 | 2223 | /ee-first/1.1.1: |
| 2143 | 2224 | resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} |
| 2144 | 2225 | dev: true |
| 2145 | 2226 | |
| 2227 | + /ejs/3.1.8: | |
| 2228 | + resolution: {integrity: sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==} | |
| 2229 | + engines: {node: '>=0.10.0'} | |
| 2230 | + hasBin: true | |
| 2231 | + dependencies: | |
| 2232 | + jake: 10.8.5 | |
| 2233 | + dev: true | |
| 2234 | + | |
| 2146 | 2235 | /electron-to-chromium/1.4.155: |
| 2147 | 2236 | resolution: {integrity: sha512-niPzKBSYPG06gxLKO0c2kEmgdRMTtIbNrBlvD31Ld8Q57b/K0218U4j8u/OOt25XE1eFOn47FcmQVdx9R1qqxA==} |
| 2148 | 2237 | dev: true |
| ... | ... | @@ -2775,6 +2864,12 @@ packages: |
| 2775 | 2864 | flat-cache: 3.0.4 |
| 2776 | 2865 | dev: true |
| 2777 | 2866 | |
| 2867 | + /filelist/1.0.4: | |
| 2868 | + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} | |
| 2869 | + dependencies: | |
| 2870 | + minimatch: 5.1.6 | |
| 2871 | + dev: true | |
| 2872 | + | |
| 2778 | 2873 | /fill-range/7.0.1: |
| 2779 | 2874 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} |
| 2780 | 2875 | engines: {node: '>=8'} |
| ... | ... | @@ -2912,7 +3007,6 @@ packages: |
| 2912 | 3007 | |
| 2913 | 3008 | /function-bind/1.1.1: |
| 2914 | 3009 | resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} |
| 2915 | - dev: true | |
| 2916 | 3010 | |
| 2917 | 3011 | /function.prototype.name/1.1.5: |
| 2918 | 3012 | resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} |
| ... | ... | @@ -2948,7 +3042,6 @@ packages: |
| 2948 | 3042 | function-bind: 1.1.1 |
| 2949 | 3043 | has: 1.0.3 |
| 2950 | 3044 | has-symbols: 1.0.3 |
| 2951 | - dev: true | |
| 2952 | 3045 | |
| 2953 | 3046 | /get-stream/6.0.1: |
| 2954 | 3047 | resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} |
| ... | ... | @@ -3111,7 +3204,6 @@ packages: |
| 3111 | 3204 | /has-symbols/1.0.3: |
| 3112 | 3205 | resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} |
| 3113 | 3206 | engines: {node: '>= 0.4'} |
| 3114 | - dev: true | |
| 3115 | 3207 | |
| 3116 | 3208 | /has-tostringtag/1.0.0: |
| 3117 | 3209 | resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} |
| ... | ... | @@ -3125,12 +3217,16 @@ packages: |
| 3125 | 3217 | engines: {node: '>= 0.4.0'} |
| 3126 | 3218 | dependencies: |
| 3127 | 3219 | function-bind: 1.1.1 |
| 3128 | - dev: true | |
| 3129 | 3220 | |
| 3130 | 3221 | /hash-sum/2.0.0: |
| 3131 | 3222 | resolution: {integrity: sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==} |
| 3132 | 3223 | dev: true |
| 3133 | 3224 | |
| 3225 | + /he/1.2.0: | |
| 3226 | + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} | |
| 3227 | + hasBin: true | |
| 3228 | + dev: true | |
| 3229 | + | |
| 3134 | 3230 | /header-case/2.0.4: |
| 3135 | 3231 | resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==} |
| 3136 | 3232 | dependencies: |
| ... | ... | @@ -3161,6 +3257,20 @@ packages: |
| 3161 | 3257 | lru-cache: 6.0.0 |
| 3162 | 3258 | dev: true |
| 3163 | 3259 | |
| 3260 | + /html-minifier-terser/6.1.0: | |
| 3261 | + resolution: {integrity: sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==} | |
| 3262 | + engines: {node: '>=12'} | |
| 3263 | + hasBin: true | |
| 3264 | + dependencies: | |
| 3265 | + camel-case: 4.1.2 | |
| 3266 | + clean-css: 5.3.2 | |
| 3267 | + commander: 8.3.0 | |
| 3268 | + he: 1.2.0 | |
| 3269 | + param-case: 3.0.4 | |
| 3270 | + relateurl: 0.2.7 | |
| 3271 | + terser: 5.16.4 | |
| 3272 | + dev: true | |
| 3273 | + | |
| 3164 | 3274 | /html-tags/3.2.0: |
| 3165 | 3275 | resolution: {integrity: sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==} |
| 3166 | 3276 | engines: {node: '>=8'} |
| ... | ... | @@ -3517,6 +3627,17 @@ packages: |
| 3517 | 3627 | engines: {node: '>=0.10.0'} |
| 3518 | 3628 | dev: true |
| 3519 | 3629 | |
| 3630 | + /jake/10.8.5: | |
| 3631 | + resolution: {integrity: sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==} | |
| 3632 | + engines: {node: '>=10'} | |
| 3633 | + hasBin: true | |
| 3634 | + dependencies: | |
| 3635 | + async: 3.2.4 | |
| 3636 | + chalk: 4.1.2 | |
| 3637 | + filelist: 1.0.4 | |
| 3638 | + minimatch: 3.1.2 | |
| 3639 | + dev: true | |
| 3640 | + | |
| 3520 | 3641 | /js-stringify/1.0.2: |
| 3521 | 3642 | resolution: {integrity: sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==} |
| 3522 | 3643 | dev: true |
| ... | ... | @@ -3591,6 +3712,10 @@ packages: |
| 3591 | 3712 | promise: 7.3.1 |
| 3592 | 3713 | dev: true |
| 3593 | 3714 | |
| 3715 | + /jwt-decode/3.1.2: | |
| 3716 | + resolution: {integrity: sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==} | |
| 3717 | + dev: false | |
| 3718 | + | |
| 3594 | 3719 | /keymaster/1.6.2: |
| 3595 | 3720 | resolution: {integrity: sha512-OvA/AALN8IDKKkTk2Z+bDrzs/SQao4lo/QPbwSdDvm+frxfiYiYCSn1aHFUypJY3SruAO1y/c771agBmTXqUtg==} |
| 3596 | 3721 | dev: false |
| ... | ... | @@ -3790,6 +3915,13 @@ packages: |
| 3790 | 3915 | brace-expansion: 1.1.11 |
| 3791 | 3916 | dev: true |
| 3792 | 3917 | |
| 3918 | + /minimatch/5.1.6: | |
| 3919 | + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} | |
| 3920 | + engines: {node: '>=10'} | |
| 3921 | + dependencies: | |
| 3922 | + brace-expansion: 2.0.1 | |
| 3923 | + dev: true | |
| 3924 | + | |
| 3793 | 3925 | /minimist-options/4.1.0: |
| 3794 | 3926 | resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} |
| 3795 | 3927 | engines: {node: '>= 6'} |
| ... | ... | @@ -3818,7 +3950,6 @@ packages: |
| 3818 | 3950 | |
| 3819 | 3951 | /monaco-editor/0.33.0: |
| 3820 | 3952 | resolution: {integrity: sha512-VcRWPSLIUEgQJQIE0pVT8FcGBIgFoxz7jtqctE+IiCxWugD0DwgyQBcZBhdSrdMC84eumoqMZsGl2GTreOzwqw==} |
| 3821 | - dev: false | |
| 3822 | 3953 | |
| 3823 | 3954 | /ms/2.0.0: |
| 3824 | 3955 | resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} |
| ... | ... | @@ -3882,6 +4013,13 @@ packages: |
| 3882 | 4013 | tslib: 2.4.0 |
| 3883 | 4014 | dev: true |
| 3884 | 4015 | |
| 4016 | + /node-html-parser/5.4.2: | |
| 4017 | + resolution: {integrity: sha512-RaBPP3+51hPne/OolXxcz89iYvQvKOydaqoePpOgXcrOKZhjVIzmpKZz+Hd/RBO2/zN2q6CNJhQzucVz+u3Jyw==} | |
| 4018 | + dependencies: | |
| 4019 | + css-select: 4.3.0 | |
| 4020 | + he: 1.2.0 | |
| 4021 | + dev: true | |
| 4022 | + | |
| 3885 | 4023 | /node-plop/0.31.0: |
| 3886 | 4024 | resolution: {integrity: sha512-aKLPxiBoFTNUovvtK8j/Whc4PZREkYx6htw2HJPiU8wYquXmN8pkd9B3xlFo6AJ4ZlzFsQSf/NXR5xET8EqRYw==} |
| 3887 | 4025 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} |
| ... | ... | @@ -3949,7 +4087,6 @@ packages: |
| 3949 | 4087 | |
| 3950 | 4088 | /object-inspect/1.12.2: |
| 3951 | 4089 | resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} |
| 3952 | - dev: true | |
| 3953 | 4090 | |
| 3954 | 4091 | /object-keys/1.1.1: |
| 3955 | 4092 | resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} |
| ... | ... | @@ -4228,6 +4365,10 @@ packages: |
| 4228 | 4365 | engines: {node: '>=8'} |
| 4229 | 4366 | dev: true |
| 4230 | 4367 | |
| 4368 | + /pathe/0.2.0: | |
| 4369 | + resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==} | |
| 4370 | + dev: true | |
| 4371 | + | |
| 4231 | 4372 | /picocolors/1.0.0: |
| 4232 | 4373 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} |
| 4233 | 4374 | |
| ... | ... | @@ -4410,6 +4551,13 @@ packages: |
| 4410 | 4551 | engines: {node: '>=0.6.0', teleport: '>=0.2.0'} |
| 4411 | 4552 | dev: true |
| 4412 | 4553 | |
| 4554 | + /qs/6.11.0: | |
| 4555 | + resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} | |
| 4556 | + engines: {node: '>=0.6'} | |
| 4557 | + dependencies: | |
| 4558 | + side-channel: 1.0.4 | |
| 4559 | + dev: false | |
| 4560 | + | |
| 4413 | 4561 | /queue-microtask/1.2.3: |
| 4414 | 4562 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} |
| 4415 | 4563 | dev: true |
| ... | ... | @@ -4487,6 +4635,11 @@ packages: |
| 4487 | 4635 | engines: {node: '>=8'} |
| 4488 | 4636 | dev: true |
| 4489 | 4637 | |
| 4638 | + /relateurl/0.2.7: | |
| 4639 | + resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==} | |
| 4640 | + engines: {node: '>= 0.10'} | |
| 4641 | + dev: true | |
| 4642 | + | |
| 4490 | 4643 | /request-light/0.5.8: |
| 4491 | 4644 | resolution: {integrity: sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==} |
| 4492 | 4645 | dev: true |
| ... | ... | @@ -4686,7 +4839,6 @@ packages: |
| 4686 | 4839 | call-bind: 1.0.2 |
| 4687 | 4840 | get-intrinsic: 1.1.2 |
| 4688 | 4841 | object-inspect: 1.12.2 |
| 4689 | - dev: true | |
| 4690 | 4842 | |
| 4691 | 4843 | /signal-exit/3.0.7: |
| 4692 | 4844 | resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} |
| ... | ... | @@ -4723,6 +4875,13 @@ packages: |
| 4723 | 4875 | resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} |
| 4724 | 4876 | engines: {node: '>=0.10.0'} |
| 4725 | 4877 | |
| 4878 | + /source-map-support/0.5.21: | |
| 4879 | + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} | |
| 4880 | + dependencies: | |
| 4881 | + buffer-from: 1.1.2 | |
| 4882 | + source-map: 0.6.1 | |
| 4883 | + dev: true | |
| 4884 | + | |
| 4726 | 4885 | /source-map/0.6.1: |
| 4727 | 4886 | resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} |
| 4728 | 4887 | engines: {node: '>=0.10.0'} |
| ... | ... | @@ -4853,6 +5012,17 @@ packages: |
| 4853 | 5012 | resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==} |
| 4854 | 5013 | dev: true |
| 4855 | 5014 | |
| 5015 | + /terser/5.16.4: | |
| 5016 | + resolution: {integrity: sha512-5yEGuZ3DZradbogeYQ1NaGz7rXVBDWujWlx1PT8efXO6Txn+eWbfKqB2bTDVmFXmePFkoLU6XI8UektMIEA0ug==} | |
| 5017 | + engines: {node: '>=10'} | |
| 5018 | + hasBin: true | |
| 5019 | + dependencies: | |
| 5020 | + '@jridgewell/source-map': 0.3.2 | |
| 5021 | + acorn: 8.7.1 | |
| 5022 | + commander: 2.20.3 | |
| 5023 | + source-map-support: 0.5.21 | |
| 5024 | + dev: true | |
| 5025 | + | |
| 4856 | 5026 | /text-extensions/1.9.0: |
| 4857 | 5027 | resolution: {integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==} |
| 4858 | 5028 | engines: {node: '>=0.10'} |
| ... | ... | @@ -4965,7 +5135,6 @@ packages: |
| 4965 | 5135 | |
| 4966 | 5136 | /tslib/2.3.0: |
| 4967 | 5137 | resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==} |
| 4968 | - dev: true | |
| 4969 | 5138 | |
| 4970 | 5139 | /tslib/2.4.0: |
| 4971 | 5140 | resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} |
| ... | ... | @@ -5017,7 +5186,6 @@ packages: |
| 5017 | 5186 | resolution: {integrity: sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==} |
| 5018 | 5187 | engines: {node: '>=4.2.0'} |
| 5019 | 5188 | hasBin: true |
| 5020 | - dev: true | |
| 5021 | 5189 | |
| 5022 | 5190 | /typescript/4.7.3: |
| 5023 | 5191 | resolution: {integrity: sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==} |
| ... | ... | @@ -5137,6 +5305,26 @@ packages: |
| 5137 | 5305 | - supports-color |
| 5138 | 5306 | dev: true |
| 5139 | 5307 | |
| 5308 | + /vite-plugin-html/3.2.0_vite@2.9.9: | |
| 5309 | + resolution: {integrity: sha512-2VLCeDiHmV/BqqNn5h2V+4280KRgQzCFN47cst3WiNK848klESPQnzuC3okH5XHtgwHH/6s1Ho/YV6yIO0pgoQ==} | |
| 5310 | + peerDependencies: | |
| 5311 | + vite: '>=2.0.0' | |
| 5312 | + dependencies: | |
| 5313 | + '@rollup/pluginutils': 4.2.1 | |
| 5314 | + colorette: 2.0.19 | |
| 5315 | + connect-history-api-fallback: 1.6.0 | |
| 5316 | + consola: 2.15.3 | |
| 5317 | + dotenv: 16.0.3 | |
| 5318 | + dotenv-expand: 8.0.3 | |
| 5319 | + ejs: 3.1.8 | |
| 5320 | + fast-glob: 3.2.11 | |
| 5321 | + fs-extra: 10.1.0 | |
| 5322 | + html-minifier-terser: 6.1.0 | |
| 5323 | + node-html-parser: 5.4.2 | |
| 5324 | + pathe: 0.2.0 | |
| 5325 | + vite: 2.9.9_sass@1.52.3 | |
| 5326 | + dev: true | |
| 5327 | + | |
| 5140 | 5328 | /vite-plugin-importer/0.2.5: |
| 5141 | 5329 | resolution: {integrity: sha512-6OtqJmVwnfw8+B4OIh7pIdXs+jLkN7g5PIqmZdpgrMYjIFMiZrcMB1zlyUQSTokKGC90KwXviO/lq1hcUBUG3Q==} |
| 5142 | 5330 | dependencies: |
| ... | ... | @@ -5437,7 +5625,6 @@ packages: |
| 5437 | 5625 | '@vue/runtime-dom': 3.2.37 |
| 5438 | 5626 | '@vue/server-renderer': 3.2.37_vue@3.2.37 |
| 5439 | 5627 | '@vue/shared': 3.2.37 |
| 5440 | - dev: false | |
| 5441 | 5628 | |
| 5442 | 5629 | /vue3-lazyload/0.2.5-beta_2yymnzrok6eda47acnj2yjm3ae: |
| 5443 | 5630 | resolution: {integrity: sha512-GVhJfL9Hcu+AvWsYmUwODivvt+gzpT0ztgAzZaUduoiTaGCv/qzhr0VwAQXfjGF3XFYFyOJsHlAi3/WE0P8XTQ==} |
| ... | ... | @@ -5603,4 +5790,3 @@ packages: |
| 5603 | 5790 | resolution: {integrity: sha512-8IiYdfwHj2rx0UeIGZGGU4WEVSDEdeVCaIg/fomejg1Xu6OifAL1GVzIPHg2D+MyUkbNgPWji90t0a8IDk+39w==} |
| 5604 | 5791 | dependencies: |
| 5605 | 5792 | tslib: 2.3.0 |
| 5606 | - dev: true | ... | ... |
src/api/external/sys/model/jwtModel.ts
0 → 100644
src/api/external/sys/model/userModel.ts
0 → 100644
| 1 | +/** | |
| 2 | + * @description: Login interface parameters | |
| 3 | + */ | |
| 4 | +export interface LoginParams { | |
| 5 | + username: string; | |
| 6 | + password: string; | |
| 7 | +} | |
| 8 | +export interface SmsLoginParams { | |
| 9 | + phoneNumber: string; | |
| 10 | + code: string; | |
| 11 | +} | |
| 12 | +export interface RefreshTokenParams { | |
| 13 | + refreshToken: string; | |
| 14 | +} | |
| 15 | + | |
| 16 | +export interface RoleInfo { | |
| 17 | + roleName: string; | |
| 18 | + value: string; | |
| 19 | +} | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * @description: Login interface return value | |
| 23 | + */ | |
| 24 | +export interface LoginResultModel { | |
| 25 | + token: string; | |
| 26 | + refreshToken: string; | |
| 27 | +} | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * @description: Get user information return value | |
| 31 | + */ | |
| 32 | +export interface GetUserInfoModel { | |
| 33 | + roles: RoleInfo[]; | |
| 34 | + // 用户id | |
| 35 | + userId: string | number; | |
| 36 | + // 用户名 | |
| 37 | + username: string; | |
| 38 | + // 真实名字 | |
| 39 | + realName: string; | |
| 40 | + // 头像 | |
| 41 | + avatar: string; | |
| 42 | + // 介绍 | |
| 43 | + desc?: string; | |
| 44 | +} | |
| 45 | +export interface UserInfoModel { | |
| 46 | + userId: string | number; | |
| 47 | + username: string; | |
| 48 | + realName: string; | |
| 49 | + avatar: string; | |
| 50 | + tenantCode: string; | |
| 51 | + tenantName: string; | |
| 52 | + roles: string[]; | |
| 53 | + plainRoles?: PlainRoleInfo[]; | |
| 54 | +} | |
| 55 | + | |
| 56 | +export interface PlainRoleInfo { | |
| 57 | + roleName: string; | |
| 58 | + roleId: string; | |
| 59 | +} | ... | ... |
src/api/external/sys/user.ts
0 → 100644
| 1 | +import { defHttp } from '@/utils/external/http/axios'; | |
| 2 | +import { | |
| 3 | + LoginParams, | |
| 4 | + LoginResultModel, | |
| 5 | + GetUserInfoModel, | |
| 6 | + UserInfoModel, | |
| 7 | + RefreshTokenParams, | |
| 8 | + SmsLoginParams, | |
| 9 | +} from './model/userModel'; | |
| 10 | + | |
| 11 | +import type { ErrorMessageMode } from '/#/external/axios'; | |
| 12 | + | |
| 13 | +enum Api { | |
| 14 | + Login = '/auth/login', | |
| 15 | + SmsCodeLogin = '/auth/code/login', | |
| 16 | + Logout = '/logout', | |
| 17 | + GetUserInfo = '/user', | |
| 18 | + GetMyInfo = '/user/me/info', | |
| 19 | + GetPermCode = '/role/me/permissions', | |
| 20 | + RefreshToken = '/auth/token', | |
| 21 | + SendLoginSmsCode = '/noauth/send_login_code/', | |
| 22 | + ResetCode = '/noauth/reset_code/', | |
| 23 | + ResetPassword = '/noauth/reset/', | |
| 24 | +} | |
| 25 | + | |
| 26 | +/** | |
| 27 | + * @description: user login api | |
| 28 | + */ | |
| 29 | +export function loginApi(params: LoginParams, mode: ErrorMessageMode = 'modal') { | |
| 30 | + return defHttp.post<LoginResultModel>( | |
| 31 | + { | |
| 32 | + url: Api.Login, | |
| 33 | + params, | |
| 34 | + }, | |
| 35 | + { | |
| 36 | + errorMessageMode: mode, | |
| 37 | + joinPrefix: false, | |
| 38 | + } | |
| 39 | + ); | |
| 40 | +} | |
| 41 | +export function getMyInfo() { | |
| 42 | + return defHttp.get<UserInfoModel>({ url: Api.GetMyInfo }); | |
| 43 | +} | |
| 44 | +/** | |
| 45 | + * @description: getUserInfo | |
| 46 | + */ | |
| 47 | +export function getUserInfo() { | |
| 48 | + return defHttp.get<GetUserInfoModel>({ url: Api.GetUserInfo }); | |
| 49 | +} | |
| 50 | + | |
| 51 | +export function getPermCode() { | |
| 52 | + return defHttp.get<string[]>({ url: Api.GetPermCode }); | |
| 53 | +} | |
| 54 | +export async function SendLoginSmsCode(phoneNumber: string) { | |
| 55 | + return await defHttp.post<boolean>({ url: Api.SendLoginSmsCode + phoneNumber }); | |
| 56 | +} | |
| 57 | +export function doLogout() { | |
| 58 | + // return defHttp.get({ url: Api.Logout }); | |
| 59 | +} | |
| 60 | +export function doRefreshToken(params: RefreshTokenParams) { | |
| 61 | + return defHttp.post<LoginResultModel>( | |
| 62 | + { | |
| 63 | + url: Api.RefreshToken, | |
| 64 | + params, | |
| 65 | + }, | |
| 66 | + { | |
| 67 | + joinPrefix: false, | |
| 68 | + } | |
| 69 | + ); | |
| 70 | +} | |
| 71 | +export function smsCodeLoginApi(params: SmsLoginParams, mode: ErrorMessageMode = 'modal') { | |
| 72 | + return defHttp.post<LoginResultModel>( | |
| 73 | + { | |
| 74 | + url: Api.SmsCodeLogin, | |
| 75 | + params, | |
| 76 | + }, | |
| 77 | + { | |
| 78 | + errorMessageMode: mode, | |
| 79 | + } | |
| 80 | + ); | |
| 81 | +} | |
| 82 | + | |
| 83 | +export const getUserToken = (id: string) => { | |
| 84 | + return defHttp.get<Record<'token' | 'refreshToken', string>>({ | |
| 85 | + url: `/third/login/id/${id}`, | |
| 86 | + }); | |
| 87 | +}; | ... | ... |
src/enums/external/cacheEnum.ts
0 → 100644
| 1 | +// token key | |
| 2 | +export const TOKEN_KEY = 'TOKEN__'; | |
| 3 | + | |
| 4 | +export const JWT_TOKEN_KEY = 'JWT_TOKEN'; | |
| 5 | + | |
| 6 | +export const REFRESH_TOKEN_KEY = 'REFRESH_TOKEN'; | |
| 7 | + | |
| 8 | +export const LOCALE_KEY = 'LOCALE__'; | |
| 9 | + | |
| 10 | +// user info key | |
| 11 | +export const USER_INFO_KEY = 'USER__INFO__'; | |
| 12 | + | |
| 13 | +// role info key | |
| 14 | +export const ROLES_KEY = 'ROLES__KEY'; | |
| 15 | + | |
| 16 | +// project config key | |
| 17 | +export const PROJ_CFG_KEY = 'PROJ__CFG__KEY__'; | |
| 18 | + | |
| 19 | +// lock info | |
| 20 | +export const LOCK_INFO_KEY = 'LOCK__INFO__KEY__'; | |
| 21 | + | |
| 22 | +export const MULTIPLE_TABS_KEY = 'MULTIPLE_TABS__KEY__'; | |
| 23 | + | |
| 24 | +export const APP_DARK_MODE_KEY_ = '__APP__DARK__MODE__'; | |
| 25 | + | |
| 26 | +// base global local key | |
| 27 | +export const APP_LOCAL_CACHE_KEY = 'COMMON__LOCAL__KEY__'; | |
| 28 | + | |
| 29 | +// base global session key | |
| 30 | +export const APP_SESSION_CACHE_KEY = 'COMMON__SESSION__KEY__'; | |
| 31 | + | |
| 32 | +export const PLATFORM = 'PLATFORM'; | |
| 33 | + | |
| 34 | +export const MENU_LIST = 'MENU_LIST'; | |
| 35 | +export enum CacheTypeEnum { | |
| 36 | + SESSION, | |
| 37 | + LOCAL, | |
| 38 | +} | ... | ... |
src/enums/external/httpEnum.ts
0 → 100644
| 1 | +/** | |
| 2 | + * @description: Request result set | |
| 3 | + */ | |
| 4 | +export enum ResultEnum { | |
| 5 | + SUCCESS = 0, | |
| 6 | + ERROR = 1, | |
| 7 | + TIMEOUT = 401, | |
| 8 | + TYPE = 'success', | |
| 9 | +} | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * @description: request method | |
| 13 | + */ | |
| 14 | +export enum RequestEnum { | |
| 15 | + GET = 'GET', | |
| 16 | + POST = 'POST', | |
| 17 | + PUT = 'PUT', | |
| 18 | + DELETE = 'DELETE', | |
| 19 | +} | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * @description: contentTyp | |
| 23 | + */ | |
| 24 | +export enum ContentTypeEnum { | |
| 25 | + // json | |
| 26 | + JSON = 'application/json;charset=UTF-8', | |
| 27 | + // form-data qs | |
| 28 | + FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8', | |
| 29 | + // form-data upload | |
| 30 | + FORM_DATA = 'multipart/form-data;charset=UTF-8', | |
| 31 | +} | ... | ... |
src/enums/external/pageEnum.ts
0 → 100644
| 1 | +export const PageEnum = { | |
| 2 | + SYSTEM_PASSWORD: '/system/changePassword', | |
| 3 | + // basic login path | |
| 4 | + BASE_LOGIN: '/login', | |
| 5 | + // basic home path | |
| 6 | + // BASE_HOME: isDolang.value == '/dashboard/workbench' ? '/dashboard/workbench' : isDolang.value, | |
| 7 | + BASE_HOME: '/dashboard/workbench', | |
| 8 | + // error page path | |
| 9 | + ERROR_PAGE: '/exception', | |
| 10 | + // error log page path | |
| 11 | + ERROR_LOG_PAGE: '/error-log/list', | |
| 12 | + //消息配置 | |
| 13 | + MESSAGE_CONFIG: '/message/config', | |
| 14 | + //设备配置 | |
| 15 | + DEVICE_PROFILE: '/product/profiles', | |
| 16 | + DEVICE_LIST: '/device/list', | |
| 17 | +}; | ... | ... |
src/enums/external/roleEnum.ts
0 → 100644
| 1 | +export enum RoleEnum { | |
| 2 | + SYS_ADMIN = 'SYS_ADMIN', | |
| 3 | + PLATFORM_ADMIN = 'PLATFORM_ADMIN', | |
| 4 | + TENANT_ADMIN = 'TENANT_ADMIN', | |
| 5 | + CUSTOMER_USER = 'CUSTOMER_USER', | |
| 6 | +} | |
| 7 | + | |
| 8 | +export function isAdmin(role: string) { | |
| 9 | + if (role === RoleEnum.SYS_ADMIN || role === RoleEnum.PLATFORM_ADMIN) { | |
| 10 | + return true; | |
| 11 | + } else if (role === RoleEnum.TENANT_ADMIN || role === RoleEnum.CUSTOMER_USER) { | |
| 12 | + return false; | |
| 13 | + } | |
| 14 | +} | |
| 15 | +// 按钮级权限控制,只针对客户 | |
| 16 | +export function authBtn(role: string): boolean { | |
| 17 | + return role !== RoleEnum.CUSTOMER_USER | |
| 18 | +} | ... | ... |
src/hooks/external/setting/index.ts
0 → 100644
| 1 | +import type { GlobConfig } from '/#/external/config'; | |
| 2 | +import { getAppEnvConfig } from '@/utils/external/env'; | |
| 3 | + | |
| 4 | +export const useGlobSetting = (): Readonly<GlobConfig> => { | |
| 5 | + const { | |
| 6 | + VITE_GLOB_APP_TITLE, | |
| 7 | + VITE_GLOB_API_URL, | |
| 8 | + VITE_GLOB_APP_SHORT_NAME, | |
| 9 | + VITE_GLOB_API_URL_PREFIX, | |
| 10 | + VITE_GLOB_UPLOAD_URL, | |
| 11 | + VITE_GLOB_CONFIGURATION, | |
| 12 | + VITE_GLOB_WEB_SOCKET, | |
| 13 | + VITE_GLOB_CONTENT_SECURITY_POLICY, | |
| 14 | + VITE_GLOB_ALARM_NOTIFY_POLLING_INTERVAL_TIME, | |
| 15 | + VITE_GLOB_ALARM_NOTIFY_DURATION, | |
| 16 | + } = getAppEnvConfig(); | |
| 17 | + | |
| 18 | + if (!/[a-zA-Z_]*/.test(VITE_GLOB_APP_SHORT_NAME)) { | |
| 19 | + console.warn( | |
| 20 | + `VITE_GLOB_APP_SHORT_NAME Variables can only be characters/underscores, please modify in the environment variables and re-running.` | |
| 21 | + ); | |
| 22 | + } | |
| 23 | + | |
| 24 | + // Take global configuration | |
| 25 | + const glob: Readonly<GlobConfig> = { | |
| 26 | + title: VITE_GLOB_APP_TITLE, | |
| 27 | + apiUrl: VITE_GLOB_API_URL, | |
| 28 | + shortName: VITE_GLOB_APP_SHORT_NAME, | |
| 29 | + urlPrefix: VITE_GLOB_API_URL_PREFIX, | |
| 30 | + uploadUrl: VITE_GLOB_UPLOAD_URL, | |
| 31 | + configurationPrefix: VITE_GLOB_CONFIGURATION, | |
| 32 | + socketUrl: VITE_GLOB_WEB_SOCKET, | |
| 33 | + securityPolicy: VITE_GLOB_CONTENT_SECURITY_POLICY, | |
| 34 | + alarmNotifyDuration: VITE_GLOB_ALARM_NOTIFY_DURATION, | |
| 35 | + alarmPollingInterval: VITE_GLOB_ALARM_NOTIFY_POLLING_INTERVAL_TIME, | |
| 36 | + }; | |
| 37 | + return glob as Readonly<GlobConfig>; | |
| 38 | +}; | ... | ... |
src/hooks/external/useMessage.ts
0 → 100644
src/settings/external/encryptionSetting.ts
0 → 100644
| 1 | +import { isDevMode } from '@/utils/external/env'; | |
| 2 | + | |
| 3 | +// System default cache time, in seconds | |
| 4 | +export const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7; | |
| 5 | + | |
| 6 | +// aes encryption key | |
| 7 | +export const cacheCipher = { | |
| 8 | + key: '_11111000001111@', | |
| 9 | + iv: '@11111000001111_', | |
| 10 | +}; | |
| 11 | + | |
| 12 | +// Whether the system cache is encrypted using aes | |
| 13 | +export const enableStorageEncryption = !isDevMode(); | ... | ... |
src/settings/external/projectSetting.ts
0 → 100644
| 1 | +import type { ProjectConfig } from '/#/external/config'; | |
| 2 | +import { CacheTypeEnum } from '@/enums/external/cacheEnum'; | |
| 3 | + | |
| 4 | + | |
| 5 | +// ! You need to clear the browser cache after the change | |
| 6 | +const setting: Partial<ProjectConfig> = { | |
| 7 | + // Whether to show the configuration button | |
| 8 | + showSettingButton: true, | |
| 9 | + | |
| 10 | + // Whether to show the theme switch button | |
| 11 | + showDarkModeToggle: true, | |
| 12 | + | |
| 13 | + // Website gray mode, open for possible mourning dates | |
| 14 | + grayMode: false, | |
| 15 | + | |
| 16 | + // Color Weakness Mode | |
| 17 | + colorWeak: false, | |
| 18 | + | |
| 19 | + // Whether to cancel the menu, the top, the multi-tab page display, for possible embedded in other systems | |
| 20 | + fullContent: false, | |
| 21 | + | |
| 22 | + | |
| 23 | + // Whether to display the logo | |
| 24 | + showLogo: true, | |
| 25 | + | |
| 26 | + // Whether to show footer | |
| 27 | + showFooter: false, | |
| 28 | + | |
| 29 | + // Whether to enable KeepAlive cache is best to close during development, otherwise the cache needs to be cleared every time | |
| 30 | + openKeepAlive: true, | |
| 31 | + | |
| 32 | + // Automatic screen lock time, 0 does not lock the screen. Unit minute default 0 | |
| 33 | + lockTime: 0, | |
| 34 | + | |
| 35 | + // Whether to show breadcrumbs | |
| 36 | + showBreadCrumb: false, | |
| 37 | + | |
| 38 | + // Whether to show the breadcrumb icon | |
| 39 | + showBreadCrumbIcon: false, | |
| 40 | + | |
| 41 | + // Use error-handler-plugin | |
| 42 | + useErrorHandle: false, | |
| 43 | + | |
| 44 | + // Whether to open back to top | |
| 45 | + useOpenBackTop: true, | |
| 46 | + | |
| 47 | + // Is it possible to embed iframe pages | |
| 48 | + canEmbedIFramePage: true, | |
| 49 | + | |
| 50 | + // Whether to delete unclosed messages and notify when switching the interface | |
| 51 | + closeMessageOnSwitch: true, | |
| 52 | + | |
| 53 | + // Whether to cancel the http request that has been sent but not responded when switching the interface. | |
| 54 | + // If it is enabled, I want to overwrite a single interface. Can be set in a separate interface | |
| 55 | + removeAllHttpPending: false, | |
| 56 | +}; | |
| 57 | + | |
| 58 | +export default setting; | ... | ... |
src/store/external/module/user.ts
0 → 100644
| 1 | +import type { UserInfo, UserUpdateInfo } from '/#/external/store'; | |
| 2 | +import type { ErrorMessageMode } from '/#/external/axios'; | |
| 3 | +import { defineStore } from 'pinia'; | |
| 4 | +import { pinia as store } from '@/store'; | |
| 5 | +import { RoleEnum } from '@/enums/external/roleEnum'; | |
| 6 | +import { PageEnum } from '@/enums/external/pageEnum'; | |
| 7 | +import { JWT_TOKEN_KEY, REFRESH_TOKEN_KEY, ROLES_KEY, USER_INFO_KEY } from '@/enums/external/cacheEnum'; | |
| 8 | +import { getAuthCache, setAuthCache } from '@/utils/external/auth'; | |
| 9 | +import { | |
| 10 | + LoginParams, | |
| 11 | + LoginResultModel, | |
| 12 | + RefreshTokenParams, | |
| 13 | + SmsLoginParams, | |
| 14 | +} from '@/api/external/sys/model/userModel'; | |
| 15 | +import { doRefreshToken, loginApi } from '@/api/external/sys/user'; | |
| 16 | +import router from '@/router'; | |
| 17 | +import { createLocalStorage } from '@/utils/external/cache'; | |
| 18 | +import { useI18n } from 'vue-i18n'; | |
| 19 | +import { useDialog } from 'naive-ui'; | |
| 20 | + | |
| 21 | +interface UserState { | |
| 22 | + platInfo: any; | |
| 23 | + enterPriseInfo: any; | |
| 24 | + userInfo: Nullable<UserInfo>; | |
| 25 | + userUpdateInfo?: Nullable<UserUpdateInfo>; | |
| 26 | + token?: string; | |
| 27 | + roleList: RoleEnum[]; | |
| 28 | + sessionTimeout?: boolean; | |
| 29 | + lastUpdateTime: number; | |
| 30 | + jwtToken?: string; | |
| 31 | + refreshToken?: string; | |
| 32 | + outTarget?: string; | |
| 33 | +} | |
| 34 | + | |
| 35 | +const storage = createLocalStorage(); | |
| 36 | +export const useUserStore = defineStore({ | |
| 37 | + id: 'app-user', | |
| 38 | + state: (): UserState => ({ | |
| 39 | + //平台信息 | |
| 40 | + platInfo: storage.get('platformInfo') || null, | |
| 41 | + enterPriseInfo: storage.get('enterPriseInfo') || null, | |
| 42 | + | |
| 43 | + // user info | |
| 44 | + userInfo: null, | |
| 45 | + userUpdateInfo: null, | |
| 46 | + // token | |
| 47 | + jwtToken: undefined, | |
| 48 | + //refresh Token | |
| 49 | + refreshToken: undefined, | |
| 50 | + // roleList | |
| 51 | + roleList: [], | |
| 52 | + // Whether the login expired | |
| 53 | + sessionTimeout: false, | |
| 54 | + // Last fetch time | |
| 55 | + lastUpdateTime: 0, | |
| 56 | + }), | |
| 57 | + | |
| 58 | + getters: { | |
| 59 | + getPlatInfo(): any { | |
| 60 | + return this.platInfo; | |
| 61 | + }, | |
| 62 | + getUserInfo(): UserInfo { | |
| 63 | + return this.userInfo || getAuthCache<UserInfo>(USER_INFO_KEY) || {}; | |
| 64 | + }, | |
| 65 | + | |
| 66 | + getUserUpdateInfo(): UserUpdateInfo { | |
| 67 | + return this.userUpdateInfo || {}; | |
| 68 | + }, | |
| 69 | + getJwtToken(): string { | |
| 70 | + return this.jwtToken || getAuthCache<string>(JWT_TOKEN_KEY); | |
| 71 | + }, | |
| 72 | + getRefreshToken(): string { | |
| 73 | + return this.refreshToken || getAuthCache<string>(REFRESH_TOKEN_KEY); | |
| 74 | + }, | |
| 75 | + getRoleList(): RoleEnum[] { | |
| 76 | + return this.roleList.length > 0 ? this.roleList : getAuthCache<RoleEnum[]>(ROLES_KEY); | |
| 77 | + }, | |
| 78 | + getSessionTimeout(): boolean { | |
| 79 | + return !!this.sessionTimeout; | |
| 80 | + }, | |
| 81 | + getLastUpdateTime(): number { | |
| 82 | + return this.lastUpdateTime; | |
| 83 | + }, | |
| 84 | + }, | |
| 85 | + actions: { | |
| 86 | + setPlatInfo(platInfo: any) { | |
| 87 | + this.platInfo = platInfo; | |
| 88 | + }, | |
| 89 | + setEnterPriseInfo(enterPriseInfo: any) { | |
| 90 | + this.enterPriseInfo = enterPriseInfo; | |
| 91 | + }, | |
| 92 | + | |
| 93 | + storeToken(jwtToken: string, refreshToken: string) { | |
| 94 | + this.jwtToken = jwtToken; | |
| 95 | + this.refreshToken = refreshToken; | |
| 96 | + setAuthCache(JWT_TOKEN_KEY, jwtToken); | |
| 97 | + setAuthCache(REFRESH_TOKEN_KEY, refreshToken); | |
| 98 | + }, | |
| 99 | + setToken(info: string | undefined) { | |
| 100 | + this.jwtToken = info; | |
| 101 | + setAuthCache(JWT_TOKEN_KEY, info); | |
| 102 | + }, | |
| 103 | + setRoleList(roleList: RoleEnum[]) { | |
| 104 | + this.roleList = roleList; | |
| 105 | + setAuthCache(ROLES_KEY, roleList); | |
| 106 | + }, | |
| 107 | + setUserInfo(info: UserInfo | null) { | |
| 108 | + this.userInfo = info; | |
| 109 | + this.lastUpdateTime = new Date().getTime(); | |
| 110 | + setAuthCache(USER_INFO_KEY, info); | |
| 111 | + }, | |
| 112 | + setUserUpdateInfo(info: UserUpdateInfo) { | |
| 113 | + this.userUpdateInfo = info; | |
| 114 | + }, | |
| 115 | + setSessionTimeout(flag: boolean) { | |
| 116 | + this.sessionTimeout = flag; | |
| 117 | + }, | |
| 118 | + resetState() { | |
| 119 | + this.userInfo = null; | |
| 120 | + this.token = ''; | |
| 121 | + this.roleList = []; | |
| 122 | + this.sessionTimeout = false; | |
| 123 | + }, | |
| 124 | + /** | |
| 125 | + * @description: login | |
| 126 | + */ | |
| 127 | + async login( | |
| 128 | + params: LoginParams & { | |
| 129 | + goHome?: boolean; | |
| 130 | + mode?: ErrorMessageMode; | |
| 131 | + } | |
| 132 | + ) { | |
| 133 | + try { | |
| 134 | + const { goHome = true, mode, ...loginParams } = params; | |
| 135 | + const data = await loginApi(loginParams, mode); | |
| 136 | + } catch (error) { | |
| 137 | + return Promise.reject(error); | |
| 138 | + } | |
| 139 | + }, | |
| 140 | + async process(data: LoginResultModel, goHome?: boolean) { | |
| 141 | + | |
| 142 | + }, | |
| 143 | + async smsCodelogin( | |
| 144 | + params: SmsLoginParams & { | |
| 145 | + goHome?: boolean; | |
| 146 | + mode?: ErrorMessageMode; | |
| 147 | + } | |
| 148 | + ) { | |
| 149 | + | |
| 150 | + }, | |
| 151 | + async getMyUserInfoAction() { | |
| 152 | + | |
| 153 | + }, | |
| 154 | + /** | |
| 155 | + * @description: logout | |
| 156 | + */ | |
| 157 | + async logout(goLogin = false) { | |
| 158 | + this.setToken(undefined); | |
| 159 | + this.setSessionTimeout(false); | |
| 160 | + setAuthCache(REFRESH_TOKEN_KEY, undefined); | |
| 161 | + this.setUserInfo(null); | |
| 162 | + goLogin && router.push(PageEnum.BASE_LOGIN); | |
| 163 | + window.localStorage.clear(); | |
| 164 | + window.localStorage.removeItem('updateUserInfo'); | |
| 165 | + }, | |
| 166 | + | |
| 167 | + async doRefresh() { | |
| 168 | + try { | |
| 169 | + const req = { refreshToken: this.refreshToken } as RefreshTokenParams; | |
| 170 | + const data = await doRefreshToken(req); | |
| 171 | + const { token, refreshToken } = data; | |
| 172 | + this.storeToken(token, refreshToken); | |
| 173 | + } catch (error) { | |
| 174 | + this.logout(); | |
| 175 | + } | |
| 176 | + }, | |
| 177 | + | |
| 178 | + /** | |
| 179 | + * @description: Confirm before logging out | |
| 180 | + */ | |
| 181 | + confirmLoginOut() { | |
| 182 | + const { warning } = useDialog(); | |
| 183 | + const { t } = useI18n(); | |
| 184 | + warning({ | |
| 185 | + type: 'warning', | |
| 186 | + title: '温馨提醒', | |
| 187 | + content: '是否确认退出系统?', | |
| 188 | + onPositiveClick: async () => { | |
| 189 | + await this.logout(true); | |
| 190 | + }, | |
| 191 | + }); | |
| 192 | + }, | |
| 193 | + }, | |
| 194 | +}); | |
| 195 | + | |
| 196 | +// Need to be used outside the setup | |
| 197 | +export function useUserStoreWithOut() { | |
| 198 | + return useUserStore(store); | |
| 199 | +} | ... | ... |
src/utils/external/auth/index.ts
0 → 100644
| 1 | +import { Persistent, BasicKeys } from '@/utils/external/cache/persistent'; | |
| 2 | +import { CacheTypeEnum } from '@/enums/external/cacheEnum'; | |
| 3 | +import projectSetting from '@/settings/external/projectSetting'; | |
| 4 | +import { JWT_TOKEN_KEY, REFRESH_TOKEN_KEY } from '@/enums/external/cacheEnum'; | |
| 5 | + | |
| 6 | +const { permissionCacheType } = projectSetting; | |
| 7 | +const isLocal = permissionCacheType === CacheTypeEnum.LOCAL; | |
| 8 | + | |
| 9 | +export function getAuthCache<T>(key: BasicKeys) { | |
| 10 | + const fn = isLocal ? Persistent.getLocal : Persistent.getSession; | |
| 11 | + return fn(key) as T; | |
| 12 | +} | |
| 13 | + | |
| 14 | +export function setAuthCache(key: BasicKeys, value: any) { | |
| 15 | + const fn = isLocal ? Persistent.setLocal : Persistent.setSession; | |
| 16 | + return fn(key, value, true); | |
| 17 | +} | |
| 18 | + | |
| 19 | +export function clearAuthCache(immediate = true) { | |
| 20 | + const fn = isLocal ? Persistent.clearLocal : Persistent.clearSession; | |
| 21 | + return fn(immediate); | |
| 22 | +} | |
| 23 | +export function getJwtToken() { | |
| 24 | + return getAuthCache(JWT_TOKEN_KEY); | |
| 25 | +} | |
| 26 | +export function getRefreshToken() { | |
| 27 | + return getAuthCache(REFRESH_TOKEN_KEY); | |
| 28 | +} | ... | ... |
src/utils/external/cache/index.ts
0 → 100644
| 1 | +import { getStorageShortName } from '@/utils/external/env'; | |
| 2 | +import { createStorage as create, CreateStorageParams } from './storageCache'; | |
| 3 | +import { enableStorageEncryption, DEFAULT_CACHE_TIME } from '@/settings/external/encryptionSetting'; | |
| 4 | + | |
| 5 | + | |
| 6 | +export type Options = Partial<CreateStorageParams>; | |
| 7 | + | |
| 8 | +const createOptions = (storage: Storage, options: Options = {}): Options => { | |
| 9 | + return { | |
| 10 | + // No encryption in debug mode | |
| 11 | + hasEncrypt: enableStorageEncryption, | |
| 12 | + storage, | |
| 13 | + prefixKey: getStorageShortName(), | |
| 14 | + ...options, | |
| 15 | + }; | |
| 16 | +}; | |
| 17 | + | |
| 18 | +export const WebStorage = create(createOptions(sessionStorage)); | |
| 19 | + | |
| 20 | +export const createStorage = (storage: Storage = sessionStorage, options: Options = {}) => { | |
| 21 | + return create(createOptions(storage, options)); | |
| 22 | +}; | |
| 23 | + | |
| 24 | +export const createSessionStorage = (options: Options = {}) => { | |
| 25 | + return createStorage(sessionStorage, { ...options, timeout: DEFAULT_CACHE_TIME }); | |
| 26 | +}; | |
| 27 | + | |
| 28 | +export const createLocalStorage = (options: Options = {}) => { | |
| 29 | + return createStorage(localStorage, { ...options, timeout: DEFAULT_CACHE_TIME }); | |
| 30 | +}; | |
| 31 | + | |
| 32 | +export default WebStorage; | ... | ... |
src/utils/external/cache/memory.ts
0 → 100644
| 1 | +export interface Cache<V = any> { | |
| 2 | + value?: V; | |
| 3 | + timeoutId?: ReturnType<typeof setTimeout>; | |
| 4 | + time?: number; | |
| 5 | + alive?: number; | |
| 6 | +} | |
| 7 | + | |
| 8 | +const NOT_ALIVE = 0; | |
| 9 | + | |
| 10 | +export class Memory<T = any, V = any> { | |
| 11 | + private cache: { [key in keyof T]?: Cache<V> } = {}; | |
| 12 | + private alive: number; | |
| 13 | + | |
| 14 | + constructor(alive = NOT_ALIVE) { | |
| 15 | + // Unit second | |
| 16 | + this.alive = alive * 1000; | |
| 17 | + } | |
| 18 | + | |
| 19 | + get getCache() { | |
| 20 | + return this.cache; | |
| 21 | + } | |
| 22 | + | |
| 23 | + setCache(cache: { [key in keyof T]?: Cache<V> }) { | |
| 24 | + this.cache = cache; | |
| 25 | + } | |
| 26 | + | |
| 27 | + // get<K extends keyof T>(key: K) { | |
| 28 | + // const item = this.getItem(key); | |
| 29 | + // const time = item?.time; | |
| 30 | + // if (!isNullOrUnDef(time) && time < new Date().getTime()) { | |
| 31 | + // this.remove(key); | |
| 32 | + // } | |
| 33 | + // return item?.value ?? undefined; | |
| 34 | + // } | |
| 35 | + | |
| 36 | + get<K extends keyof T>(key: K) { | |
| 37 | + return this.cache[key]; | |
| 38 | + } | |
| 39 | + | |
| 40 | + set<K extends keyof T>(key: K, value: V, expires?: number) { | |
| 41 | + let item = this.get(key); | |
| 42 | + | |
| 43 | + if (!expires || (expires as number) <= 0) { | |
| 44 | + expires = this.alive; | |
| 45 | + } | |
| 46 | + if (item) { | |
| 47 | + if (item.timeoutId) { | |
| 48 | + clearTimeout(item.timeoutId); | |
| 49 | + item.timeoutId = undefined; | |
| 50 | + } | |
| 51 | + item.value = value; | |
| 52 | + } else { | |
| 53 | + item = { value, alive: expires }; | |
| 54 | + this.cache[key] = item; | |
| 55 | + } | |
| 56 | + | |
| 57 | + if (!expires) { | |
| 58 | + return value; | |
| 59 | + } | |
| 60 | + const now = new Date().getTime(); | |
| 61 | + item.time = now + this.alive; | |
| 62 | + item.timeoutId = setTimeout( | |
| 63 | + () => { | |
| 64 | + this.remove(key); | |
| 65 | + }, | |
| 66 | + expires > now ? expires - now : expires | |
| 67 | + ); | |
| 68 | + | |
| 69 | + return value; | |
| 70 | + } | |
| 71 | + | |
| 72 | + remove<K extends keyof T>(key: K) { | |
| 73 | + const item = this.get(key); | |
| 74 | + Reflect.deleteProperty(this.cache, key); | |
| 75 | + if (item) { | |
| 76 | + clearTimeout(item.timeoutId!); | |
| 77 | + return item.value; | |
| 78 | + } | |
| 79 | + } | |
| 80 | + | |
| 81 | + resetCache(cache: { [K in keyof T]: Cache }) { | |
| 82 | + Object.keys(cache).forEach((key) => { | |
| 83 | + const k = key as any as keyof T; | |
| 84 | + const item = cache[k]; | |
| 85 | + if (item && item.time) { | |
| 86 | + const now = new Date().getTime(); | |
| 87 | + const expire = item.time; | |
| 88 | + if (expire > now) { | |
| 89 | + this.set(k, item.value, expire); | |
| 90 | + } | |
| 91 | + } | |
| 92 | + }); | |
| 93 | + } | |
| 94 | + | |
| 95 | + clear() { | |
| 96 | + Object.keys(this.cache).forEach((key) => { | |
| 97 | + const item: Cache<V> = this.cache[key as keyof T]!; | |
| 98 | + item.timeoutId && clearTimeout(item.timeoutId); | |
| 99 | + }); | |
| 100 | + this.cache = {}; | |
| 101 | + } | |
| 102 | +} | ... | ... |
src/utils/external/cache/persistent.ts
0 → 100644
| 1 | +import type { LockInfo, UserInfo } from '/#/external/store'; | |
| 2 | +import type { ProjectConfig } from '/#/external/config'; | |
| 3 | +import type { RouteLocationNormalized } from 'vue-router'; | |
| 4 | + | |
| 5 | +import { createLocalStorage, createSessionStorage } from '@/utils/external/cache'; | |
| 6 | +import { Memory } from './memory'; | |
| 7 | +import { | |
| 8 | + PLATFORM, | |
| 9 | + TOKEN_KEY, | |
| 10 | + JWT_TOKEN_KEY, | |
| 11 | + REFRESH_TOKEN_KEY, | |
| 12 | + USER_INFO_KEY, | |
| 13 | + ROLES_KEY, | |
| 14 | + LOCK_INFO_KEY, | |
| 15 | + PROJ_CFG_KEY, | |
| 16 | + APP_LOCAL_CACHE_KEY, | |
| 17 | + APP_SESSION_CACHE_KEY, | |
| 18 | + MULTIPLE_TABS_KEY, | |
| 19 | + MENU_LIST, | |
| 20 | +} from '@/enums/external/cacheEnum'; | |
| 21 | +import { DEFAULT_CACHE_TIME } from '@/settings/external/encryptionSetting'; | |
| 22 | +import { toRaw } from 'vue'; | |
| 23 | +import omit from 'lodash/omit'; | |
| 24 | +import pick from 'lodash/pick'; | |
| 25 | + | |
| 26 | +interface BasicStore { | |
| 27 | + [PLATFORM]: Object; | |
| 28 | + [TOKEN_KEY]: string | number | null | undefined; | |
| 29 | + [JWT_TOKEN_KEY]: string | number | null | undefined; | |
| 30 | + [REFRESH_TOKEN_KEY]: string | number | null | undefined; | |
| 31 | + [USER_INFO_KEY]: UserInfo; | |
| 32 | + [ROLES_KEY]: string[]; | |
| 33 | + [LOCK_INFO_KEY]: LockInfo; | |
| 34 | + [PROJ_CFG_KEY]: ProjectConfig; | |
| 35 | + [MULTIPLE_TABS_KEY]: RouteLocationNormalized[]; | |
| 36 | + [MENU_LIST]: any[]; | |
| 37 | +} | |
| 38 | + | |
| 39 | +type LocalStore = BasicStore; | |
| 40 | + | |
| 41 | +type SessionStore = BasicStore; | |
| 42 | + | |
| 43 | +export type BasicKeys = keyof BasicStore; | |
| 44 | +type LocalKeys = keyof LocalStore; | |
| 45 | +type SessionKeys = keyof SessionStore; | |
| 46 | + | |
| 47 | +const ls = createLocalStorage(); | |
| 48 | +const ss = createSessionStorage(); | |
| 49 | + | |
| 50 | +const localMemory = new Memory(DEFAULT_CACHE_TIME); | |
| 51 | +const sessionMemory = new Memory(DEFAULT_CACHE_TIME); | |
| 52 | + | |
| 53 | +function initPersistentMemory() { | |
| 54 | + const localCache = ls.get(APP_LOCAL_CACHE_KEY); | |
| 55 | + const sessionCache = ss.get(APP_SESSION_CACHE_KEY); | |
| 56 | + localCache && localMemory.resetCache(localCache); | |
| 57 | + sessionCache && sessionMemory.resetCache(sessionCache); | |
| 58 | +} | |
| 59 | + | |
| 60 | +export class Persistent { | |
| 61 | + static getLocal<T>(key: LocalKeys) { | |
| 62 | + return localMemory.get(key)?.value as Nullable<T>; | |
| 63 | + } | |
| 64 | + | |
| 65 | + static setLocal(key: LocalKeys, value: LocalStore[LocalKeys], immediate = false): void { | |
| 66 | + localMemory.set(key, toRaw(value)); | |
| 67 | + immediate && ls.set(APP_LOCAL_CACHE_KEY, localMemory.getCache); | |
| 68 | + } | |
| 69 | + | |
| 70 | + static removeLocal(key: LocalKeys, immediate = false): void { | |
| 71 | + localMemory.remove(key); | |
| 72 | + immediate && ls.set(APP_LOCAL_CACHE_KEY, localMemory.getCache); | |
| 73 | + } | |
| 74 | + | |
| 75 | + static clearLocal(immediate = false): void { | |
| 76 | + localMemory.clear(); | |
| 77 | + immediate && ls.clear(); | |
| 78 | + } | |
| 79 | + | |
| 80 | + static getSession<T>(key: SessionKeys) { | |
| 81 | + return sessionMemory.get(key)?.value as Nullable<T>; | |
| 82 | + } | |
| 83 | + | |
| 84 | + static setSession(key: SessionKeys, value: SessionStore[SessionKeys], immediate = false): void { | |
| 85 | + sessionMemory.set(key, toRaw(value)); | |
| 86 | + immediate && ss.set(APP_SESSION_CACHE_KEY, sessionMemory.getCache); | |
| 87 | + } | |
| 88 | + | |
| 89 | + static removeSession(key: SessionKeys, immediate = false): void { | |
| 90 | + sessionMemory.remove(key); | |
| 91 | + immediate && ss.set(APP_SESSION_CACHE_KEY, sessionMemory.getCache); | |
| 92 | + } | |
| 93 | + static clearSession(immediate = false): void { | |
| 94 | + sessionMemory.clear(); | |
| 95 | + immediate && ss.clear(); | |
| 96 | + } | |
| 97 | + | |
| 98 | + static clearAll(immediate = false) { | |
| 99 | + sessionMemory.clear(); | |
| 100 | + localMemory.clear(); | |
| 101 | + if (immediate) { | |
| 102 | + ls.clear(); | |
| 103 | + ss.clear(); | |
| 104 | + } | |
| 105 | + } | |
| 106 | +} | |
| 107 | + | |
| 108 | +window.addEventListener('beforeunload', function () { | |
| 109 | + // TOKEN_KEY 在登录或注销时已经写入到storage了,此处为了解决同时打开多个窗口时token不同步的问题 | |
| 110 | + // LOCK_INFO_KEY 在锁屏和解锁时写入,此处也不应修改 | |
| 111 | + ls.set(APP_LOCAL_CACHE_KEY, { | |
| 112 | + ...omit(localMemory.getCache, LOCK_INFO_KEY), | |
| 113 | + ...pick(ls.get(APP_LOCAL_CACHE_KEY), [ | |
| 114 | + TOKEN_KEY, | |
| 115 | + JWT_TOKEN_KEY, | |
| 116 | + REFRESH_TOKEN_KEY, | |
| 117 | + USER_INFO_KEY, | |
| 118 | + LOCK_INFO_KEY, | |
| 119 | + ROLES_KEY, | |
| 120 | + ]), | |
| 121 | + }); | |
| 122 | + ss.set(APP_SESSION_CACHE_KEY, { | |
| 123 | + ...omit(sessionMemory.getCache, LOCK_INFO_KEY), | |
| 124 | + ...pick(ss.get(APP_SESSION_CACHE_KEY), [ | |
| 125 | + TOKEN_KEY, | |
| 126 | + JWT_TOKEN_KEY, | |
| 127 | + REFRESH_TOKEN_KEY, | |
| 128 | + USER_INFO_KEY, | |
| 129 | + LOCK_INFO_KEY, | |
| 130 | + ROLES_KEY, | |
| 131 | + ]), | |
| 132 | + }); | |
| 133 | +}); | |
| 134 | + | |
| 135 | +function storageChange(e: any) { | |
| 136 | + const { key, newValue, oldValue } = e; | |
| 137 | + | |
| 138 | + if (!key) { | |
| 139 | + Persistent.clearAll(); | |
| 140 | + return; | |
| 141 | + } | |
| 142 | + | |
| 143 | + if (!!newValue && !!oldValue) { | |
| 144 | + if (APP_LOCAL_CACHE_KEY === key) { | |
| 145 | + Persistent.clearLocal(); | |
| 146 | + } | |
| 147 | + if (APP_SESSION_CACHE_KEY === key) { | |
| 148 | + Persistent.clearSession(); | |
| 149 | + } | |
| 150 | + } | |
| 151 | +} | |
| 152 | + | |
| 153 | +window.addEventListener('storage', storageChange); | |
| 154 | + | |
| 155 | +initPersistentMemory(); | ... | ... |
src/utils/external/cache/storageCache.ts
0 → 100644
| 1 | +import { cacheCipher } from '@/settings/external/encryptionSetting'; | |
| 2 | + | |
| 3 | +import type { EncryptionParams } from '@/utils/external/cipher'; | |
| 4 | + | |
| 5 | +import { AesEncryption } from '@/utils/external/cipher'; | |
| 6 | + | |
| 7 | +import { isNullOrUnDef } from '@/utils/external/is'; | |
| 8 | + | |
| 9 | +export interface CreateStorageParams extends EncryptionParams { | |
| 10 | + prefixKey: string; | |
| 11 | + storage: Storage; | |
| 12 | + hasEncrypt: boolean; | |
| 13 | + timeout?: Nullable<number>; | |
| 14 | +} | |
| 15 | +export const createStorage = ({ | |
| 16 | + prefixKey = '', | |
| 17 | + storage = sessionStorage, | |
| 18 | + key = cacheCipher.key, | |
| 19 | + iv = cacheCipher.iv, | |
| 20 | + timeout = null, | |
| 21 | + hasEncrypt = true, | |
| 22 | +}: Partial<CreateStorageParams> = {}) => { | |
| 23 | + if (hasEncrypt && [key.length, iv.length].some((item) => item !== 16)) { | |
| 24 | + throw new Error('When hasEncrypt is true, the key or iv must be 16 bits!'); | |
| 25 | + } | |
| 26 | + | |
| 27 | + const encryption = new AesEncryption({ key, iv }); | |
| 28 | + | |
| 29 | + /** | |
| 30 | + *Cache class | |
| 31 | + *Construction parameters can be passed into sessionStorage, localStorage, | |
| 32 | + * @class Cache | |
| 33 | + * @example | |
| 34 | + */ | |
| 35 | + const WebStorage = class WebStorage { | |
| 36 | + private storage: Storage; | |
| 37 | + private prefixKey?: string; | |
| 38 | + private encryption: AesEncryption; | |
| 39 | + private hasEncrypt: boolean; | |
| 40 | + /** | |
| 41 | + * | |
| 42 | + * @param {*} storage | |
| 43 | + */ | |
| 44 | + constructor() { | |
| 45 | + this.storage = storage; | |
| 46 | + this.prefixKey = prefixKey; | |
| 47 | + this.encryption = encryption; | |
| 48 | + this.hasEncrypt = hasEncrypt; | |
| 49 | + } | |
| 50 | + | |
| 51 | + private getKey(key: string) { | |
| 52 | + return `${this.prefixKey}${key}`.toUpperCase(); | |
| 53 | + } | |
| 54 | + | |
| 55 | + /** | |
| 56 | + * | |
| 57 | + * Set cache | |
| 58 | + * @param {string} key | |
| 59 | + * @param {*} value | |
| 60 | + * @expire Expiration time in seconds | |
| 61 | + * @memberof Cache | |
| 62 | + */ | |
| 63 | + set(key: string, value: any, expire: number | null = timeout) { | |
| 64 | + const stringData = JSON.stringify({ | |
| 65 | + value, | |
| 66 | + time: Date.now(), | |
| 67 | + expire: !isNullOrUnDef(expire) ? new Date().getTime() + expire * 1000 : null, | |
| 68 | + }); | |
| 69 | + const stringifyValue = this.hasEncrypt | |
| 70 | + ? this.encryption.encryptByAES(stringData) | |
| 71 | + : stringData; | |
| 72 | + this.storage.setItem(this.getKey(key), stringifyValue); | |
| 73 | + } | |
| 74 | + | |
| 75 | + /** | |
| 76 | + *Read cache | |
| 77 | + * @param {string} key | |
| 78 | + * @memberof Cache | |
| 79 | + */ | |
| 80 | + get(key: string, def: any = null): any { | |
| 81 | + const val = this.storage.getItem(this.getKey(key)); | |
| 82 | + if (!val) return def; | |
| 83 | + | |
| 84 | + try { | |
| 85 | + const decVal = this.hasEncrypt ? this.encryption.decryptByAES(val) : val; | |
| 86 | + const data = JSON.parse(decVal); | |
| 87 | + const { value, expire } = data; | |
| 88 | + if (isNullOrUnDef(expire) || expire >= new Date().getTime()) { | |
| 89 | + return value; | |
| 90 | + } | |
| 91 | + this.remove(key); | |
| 92 | + } catch (e) { | |
| 93 | + return def; | |
| 94 | + } | |
| 95 | + } | |
| 96 | + | |
| 97 | + /** | |
| 98 | + * Delete cache based on key | |
| 99 | + * @param {string} key | |
| 100 | + * @memberof Cache | |
| 101 | + */ | |
| 102 | + remove(key: string) { | |
| 103 | + this.storage.removeItem(this.getKey(key)); | |
| 104 | + } | |
| 105 | + | |
| 106 | + /** | |
| 107 | + * Delete all caches of this instance | |
| 108 | + */ | |
| 109 | + clear(): void { | |
| 110 | + this.storage.clear(); | |
| 111 | + } | |
| 112 | + }; | |
| 113 | + return new WebStorage(); | |
| 114 | +}; | ... | ... |
src/utils/external/cipher.ts
0 → 100644
| 1 | +import { encrypt, decrypt } from 'crypto-js/aes'; | |
| 2 | +import { parse } from 'crypto-js/enc-utf8'; | |
| 3 | +import pkcs7 from 'crypto-js/pad-pkcs7'; | |
| 4 | +import ECB from 'crypto-js/mode-ecb'; | |
| 5 | +import md5 from 'crypto-js/md5'; | |
| 6 | +import UTF8 from 'crypto-js/enc-utf8'; | |
| 7 | +import Base64 from 'crypto-js/enc-base64'; | |
| 8 | + | |
| 9 | +export interface EncryptionParams { | |
| 10 | + key: string; | |
| 11 | + iv: string; | |
| 12 | +} | |
| 13 | + | |
| 14 | +export class AesEncryption { | |
| 15 | + private key; | |
| 16 | + private iv; | |
| 17 | + | |
| 18 | + constructor(opt: Partial<EncryptionParams> = {}) { | |
| 19 | + const { key, iv } = opt; | |
| 20 | + if (key) { | |
| 21 | + this.key = parse(key); | |
| 22 | + } | |
| 23 | + if (iv) { | |
| 24 | + this.iv = parse(iv); | |
| 25 | + } | |
| 26 | + } | |
| 27 | + | |
| 28 | + get getOptions() { | |
| 29 | + return { | |
| 30 | + mode: ECB, | |
| 31 | + padding: pkcs7, | |
| 32 | + iv: this.iv, | |
| 33 | + }; | |
| 34 | + } | |
| 35 | + | |
| 36 | + encryptByAES(cipherText: string) { | |
| 37 | + return encrypt(cipherText, this.key!, this.getOptions).toString(); | |
| 38 | + } | |
| 39 | + | |
| 40 | + decryptByAES(cipherText: string) { | |
| 41 | + return decrypt(cipherText, this.key!, this.getOptions).toString(UTF8); | |
| 42 | + } | |
| 43 | +} | |
| 44 | + | |
| 45 | +export function encryptByBase64(cipherText: string) { | |
| 46 | + return UTF8.parse(cipherText).toString(Base64); | |
| 47 | +} | |
| 48 | + | |
| 49 | +export function decodeByBase64(cipherText: string) { | |
| 50 | + return Base64.parse(cipherText).toString(UTF8); | |
| 51 | +} | |
| 52 | + | |
| 53 | +export function encryptByMd5(password: string) { | |
| 54 | + return md5(password).toString(); | |
| 55 | +} | ... | ... |
src/utils/external/env/index.ts
0 → 100644
| 1 | +import type { GlobEnvConfig } from '/#/external/config'; | |
| 2 | + | |
| 3 | +import pkg from '../../../../package.json'; | |
| 4 | +import { getGlobalConfigName } from 'build/external/globConfig/getGlobConfigName'; | |
| 5 | + | |
| 6 | +export function getCommonStoragePrefix() { | |
| 7 | + const { VITE_GLOB_APP_SHORT_NAME } = getAppEnvConfig(); | |
| 8 | + return `${VITE_GLOB_APP_SHORT_NAME}__${getEnv()}`.toUpperCase(); | |
| 9 | +} | |
| 10 | + | |
| 11 | +// Generate cache key according to version | |
| 12 | +export function getStorageShortName() { | |
| 13 | + return `${getCommonStoragePrefix()}${`__${pkg.version}`}__`.toUpperCase(); | |
| 14 | +} | |
| 15 | + | |
| 16 | +export function getAppEnvConfig() { | |
| 17 | + const ENV_NAME = getGlobalConfigName(import.meta.env); | |
| 18 | + | |
| 19 | + const ENV = (import.meta.env.DEV | |
| 20 | + ? // Get the global configuration (the configuration will be extracted independently when packaging) | |
| 21 | + (import.meta.env as unknown as GlobEnvConfig) | |
| 22 | + : window[ENV_NAME as any]) as unknown as GlobEnvConfig; | |
| 23 | + const { | |
| 24 | + VITE_GLOB_APP_TITLE, | |
| 25 | + VITE_GLOB_API_URL, | |
| 26 | + VITE_GLOB_APP_SHORT_NAME, | |
| 27 | + VITE_GLOB_API_URL_PREFIX, | |
| 28 | + VITE_GLOB_UPLOAD_URL, | |
| 29 | + VITE_GLOB_CONFIGURATION, | |
| 30 | + VITE_GLOB_WEB_SOCKET, | |
| 31 | + VITE_GLOB_CONTENT_SECURITY_POLICY, | |
| 32 | + VITE_GLOB_ALARM_NOTIFY_POLLING_INTERVAL_TIME, | |
| 33 | + VITE_GLOB_ALARM_NOTIFY_DURATION, | |
| 34 | + } = ENV; | |
| 35 | + | |
| 36 | + if (!/^[a-zA-Z\_]*$/.test(VITE_GLOB_APP_SHORT_NAME)) { | |
| 37 | + console.warn( | |
| 38 | + `VITE_GLOB_APP_SHORT_NAME Variables can only be characters/underscores, please modify in the environment variables and re-running.` | |
| 39 | + ); | |
| 40 | + } | |
| 41 | + | |
| 42 | + return { | |
| 43 | + VITE_GLOB_APP_TITLE, | |
| 44 | + VITE_GLOB_API_URL, | |
| 45 | + VITE_GLOB_APP_SHORT_NAME, | |
| 46 | + VITE_GLOB_API_URL_PREFIX, | |
| 47 | + VITE_GLOB_UPLOAD_URL, | |
| 48 | + VITE_GLOB_CONFIGURATION, | |
| 49 | + VITE_GLOB_WEB_SOCKET, | |
| 50 | + VITE_GLOB_CONTENT_SECURITY_POLICY, | |
| 51 | + VITE_GLOB_ALARM_NOTIFY_POLLING_INTERVAL_TIME, | |
| 52 | + VITE_GLOB_ALARM_NOTIFY_DURATION, | |
| 53 | + }; | |
| 54 | +} | |
| 55 | + | |
| 56 | +/** | |
| 57 | + * @description: Development mode | |
| 58 | + */ | |
| 59 | +export const devMode = 'development'; | |
| 60 | + | |
| 61 | +/** | |
| 62 | + * @description: Production mode | |
| 63 | + */ | |
| 64 | +export const prodMode = 'production'; | |
| 65 | + | |
| 66 | +/** | |
| 67 | + * @description: Get environment variables | |
| 68 | + * @returns: | |
| 69 | + * @example: | |
| 70 | + */ | |
| 71 | +export function getEnv(): string { | |
| 72 | + return import.meta.env.MODE; | |
| 73 | +} | |
| 74 | + | |
| 75 | +/** | |
| 76 | + * @description: Is it a development mode | |
| 77 | + * @returns: | |
| 78 | + * @example: | |
| 79 | + */ | |
| 80 | +export function isDevMode(): boolean { | |
| 81 | + return import.meta.env.DEV; | |
| 82 | +} | |
| 83 | + | |
| 84 | +/** | |
| 85 | + * @description: Is it a production mode | |
| 86 | + * @returns: | |
| 87 | + * @example: | |
| 88 | + */ | |
| 89 | +export function isProdMode(): boolean { | |
| 90 | + return import.meta.env.PROD; | |
| 91 | +} | ... | ... |
src/utils/external/http/axios/Axios.ts
0 → 100644
| 1 | +import type { AxiosRequestConfig, AxiosInstance, AxiosResponse, AxiosError } from 'axios'; | |
| 2 | +import type { CreateAxiosOptions } from './axiosTransform'; | |
| 3 | +import axios from 'axios'; | |
| 4 | +import qs from 'qs'; | |
| 5 | +import { AxiosCanceler } from './axiosCancel'; | |
| 6 | +import jwt_decode from 'jwt-decode'; | |
| 7 | +import { RequestOptions, Result, UploadFileParams } from '/#/external/axios'; | |
| 8 | +import { JwtModel } from '@/api/external/sys/model/jwtModel'; | |
| 9 | +import { isFunction } from '@/utils/external/is' | |
| 10 | +import { ContentTypeEnum, RequestEnum } from '@/enums/external/httpEnum'; | |
| 11 | +import omit from 'lodash/omit'; | |
| 12 | +import cloneDeep from 'lodash/cloneDeep'; | |
| 13 | +import { useUserStore } from '@/store/external/module/user'; | |
| 14 | + | |
| 15 | +export * from './axiosTransform'; | |
| 16 | + | |
| 17 | +/** | |
| 18 | + * @description: axios module | |
| 19 | + */ | |
| 20 | +export class VAxios { | |
| 21 | + private axiosInstance: AxiosInstance; | |
| 22 | + private readonly options: CreateAxiosOptions; | |
| 23 | + private waitingQueue: any[]; | |
| 24 | + private refreshing = false; | |
| 25 | + | |
| 26 | + constructor(options: CreateAxiosOptions) { | |
| 27 | + this.options = options; | |
| 28 | + this.axiosInstance = axios.create(options); | |
| 29 | + this.setupInterceptors(); | |
| 30 | + this.waitingQueue = []; | |
| 31 | + } | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * @description: Create axios instance | |
| 35 | + */ | |
| 36 | + private createAxios(config: CreateAxiosOptions): void { | |
| 37 | + this.axiosInstance = axios.create(config); | |
| 38 | + } | |
| 39 | + | |
| 40 | + private getTransform() { | |
| 41 | + const { transform } = this.options; | |
| 42 | + return transform; | |
| 43 | + } | |
| 44 | + | |
| 45 | + getAxios(): AxiosInstance { | |
| 46 | + return this.axiosInstance; | |
| 47 | + } | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * @description: Reconfigure axios | |
| 51 | + */ | |
| 52 | + configAxios(config: CreateAxiosOptions) { | |
| 53 | + if (!this.axiosInstance) { | |
| 54 | + return; | |
| 55 | + } | |
| 56 | + this.createAxios(config); | |
| 57 | + } | |
| 58 | + | |
| 59 | + /** | |
| 60 | + * @description: Set general header | |
| 61 | + */ | |
| 62 | + setHeader(headers: any): void { | |
| 63 | + if (!this.axiosInstance) { | |
| 64 | + return; | |
| 65 | + } | |
| 66 | + Object.assign(this.axiosInstance.defaults.headers, headers); | |
| 67 | + } | |
| 68 | + /** | |
| 69 | + * JWT 自动刷新 | |
| 70 | + * @description: 自动刷新token | |
| 71 | + */ | |
| 72 | + private isNeedTokenURL(url: string, arr = ['/auth/login', '/auth/token']) { | |
| 73 | + return !arr.some((val) => url.indexOf(val) > -1); | |
| 74 | + } | |
| 75 | + | |
| 76 | + /** | |
| 77 | + * | |
| 78 | + * @returns | |
| 79 | + */ | |
| 80 | + private refreshTokenBeforeReq(doRefreshTokenApi: () => Promise<unknown>): Promise<unknown> { | |
| 81 | + // 创建一个未完成的promise,把改变状态的resolve方法交给请求token结束后执行 | |
| 82 | + const promise = new Promise((resolve) => { | |
| 83 | + // 等待队列放的是一个回调函数,来延迟resolve的执行,以此控制promise状态的改变 | |
| 84 | + this.waitingQueue.push(() => resolve(null)); | |
| 85 | + }); | |
| 86 | + if (!this.refreshing) { | |
| 87 | + this.refreshing = true; | |
| 88 | + // 模拟请求刷新Token接口,当接口返回数据时执行then方法 TODO 添加catch捕获异常 | |
| 89 | + doRefreshTokenApi().then(() => { | |
| 90 | + this.refreshing = false; | |
| 91 | + this.waitingQueue.forEach((cb) => cb()); | |
| 92 | + this.waitingQueue.length = 0; | |
| 93 | + }); | |
| 94 | + } | |
| 95 | + return promise; | |
| 96 | + } | |
| 97 | + /** | |
| 98 | + * @description: Interceptor configuration | |
| 99 | + */ | |
| 100 | + private setupInterceptors() { | |
| 101 | + const transform = this.getTransform(); | |
| 102 | + if (!transform) { | |
| 103 | + return; | |
| 104 | + } | |
| 105 | + const { | |
| 106 | + requestInterceptors, | |
| 107 | + requestInterceptorsCatch, | |
| 108 | + responseInterceptors, | |
| 109 | + responseInterceptorsCatch, | |
| 110 | + } = transform; | |
| 111 | + | |
| 112 | + const axiosCanceler = new AxiosCanceler(); | |
| 113 | + | |
| 114 | + // Request interceptor configuration processing | |
| 115 | + this.axiosInstance.interceptors.request.use(async (config: AxiosRequestConfig) => { | |
| 116 | + // If cancel repeat request is turned on, then cancel repeat request is prohibited | |
| 117 | + const userStore = useUserStore(); | |
| 118 | + if (userStore && userStore.jwtToken) { | |
| 119 | + try { | |
| 120 | + const res = jwt_decode(userStore.jwtToken) as JwtModel; | |
| 121 | + const currentTime = new Date().getTime() / 1000; | |
| 122 | + if (currentTime >= res.exp && this.isNeedTokenURL(config.url!)) { | |
| 123 | + await this.refreshTokenBeforeReq(userStore.doRefresh); | |
| 124 | + } | |
| 125 | + } catch (error) { | |
| 126 | + userStore.logout(); | |
| 127 | + } | |
| 128 | + } | |
| 129 | + const { | |
| 130 | + headers: { ignoreCancelToken } = {}, | |
| 131 | + } = config; | |
| 132 | + | |
| 133 | + const ignoreCancel = | |
| 134 | + ignoreCancelToken !== undefined | |
| 135 | + ? ignoreCancelToken | |
| 136 | + : this.options.requestOptions?.ignoreCancelToken; | |
| 137 | + | |
| 138 | + !ignoreCancel && axiosCanceler.addPending(config); | |
| 139 | + if (requestInterceptors && isFunction(requestInterceptors)) { | |
| 140 | + config = requestInterceptors(config, this.options); | |
| 141 | + } | |
| 142 | + return config; | |
| 143 | + }, undefined); | |
| 144 | + | |
| 145 | + // Request interceptor error capture | |
| 146 | + requestInterceptorsCatch && | |
| 147 | + isFunction(requestInterceptorsCatch) && | |
| 148 | + this.axiosInstance.interceptors.request.use(undefined, requestInterceptorsCatch); | |
| 149 | + | |
| 150 | + // Response result interceptor processing | |
| 151 | + this.axiosInstance.interceptors.response.use((res: AxiosResponse<any>) => { | |
| 152 | + res && axiosCanceler.removePending(res.config); | |
| 153 | + if (responseInterceptors && isFunction(responseInterceptors)) { | |
| 154 | + res = responseInterceptors(res); | |
| 155 | + } | |
| 156 | + return res; | |
| 157 | + }, undefined); | |
| 158 | + | |
| 159 | + // Response result interceptor error capture | |
| 160 | + responseInterceptorsCatch && | |
| 161 | + isFunction(responseInterceptorsCatch) && | |
| 162 | + this.axiosInstance.interceptors.response.use(undefined, responseInterceptorsCatch); | |
| 163 | + } | |
| 164 | + | |
| 165 | + /** | |
| 166 | + * @description: File Upload | |
| 167 | + */ | |
| 168 | + uploadFile<T = any>(config: AxiosRequestConfig, params: UploadFileParams) { | |
| 169 | + const formData = new window.FormData(); | |
| 170 | + | |
| 171 | + if (params.data) { | |
| 172 | + Object.keys(params.data).forEach((key) => { | |
| 173 | + if (!params.data) return; | |
| 174 | + const value = params.data[key]; | |
| 175 | + if (Array.isArray(value)) { | |
| 176 | + value.forEach((item) => { | |
| 177 | + formData.append(`${key}[]`, item); | |
| 178 | + }); | |
| 179 | + return; | |
| 180 | + } | |
| 181 | + | |
| 182 | + formData.append(key, params.data[key]); | |
| 183 | + }); | |
| 184 | + } | |
| 185 | + formData.append(params.name || 'file', params.file, params.filename); | |
| 186 | + const customParams = omit(params, 'file', 'filename', 'file'); | |
| 187 | + | |
| 188 | + Object.keys(customParams).forEach((key) => { | |
| 189 | + formData.append(key, customParams[key]); | |
| 190 | + }); | |
| 191 | + | |
| 192 | + return this.axiosInstance.request<T>({ | |
| 193 | + ...config, | |
| 194 | + method: 'POST', | |
| 195 | + data: formData, | |
| 196 | + headers: { | |
| 197 | + 'Content-type': ContentTypeEnum.FORM_DATA, | |
| 198 | + ignoreCancelToken: true, | |
| 199 | + }, | |
| 200 | + }); | |
| 201 | + } | |
| 202 | + | |
| 203 | + // support form-data | |
| 204 | + supportFormData(config: AxiosRequestConfig) { | |
| 205 | + const headers = config.headers || this.options.headers; | |
| 206 | + const contentType = headers?.['Content-Type'] || headers?.['content-type']; | |
| 207 | + | |
| 208 | + if ( | |
| 209 | + contentType !== ContentTypeEnum.FORM_URLENCODED || | |
| 210 | + !Reflect.has(config, 'data') || | |
| 211 | + config.method?.toUpperCase() === RequestEnum.GET | |
| 212 | + ) { | |
| 213 | + return config; | |
| 214 | + } | |
| 215 | + | |
| 216 | + return { | |
| 217 | + ...config, | |
| 218 | + data: qs.stringify(config.data, { arrayFormat: 'brackets' }), | |
| 219 | + }; | |
| 220 | + } | |
| 221 | + | |
| 222 | + get<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> { | |
| 223 | + return this.request({ ...config, method: 'GET' }, options); | |
| 224 | + } | |
| 225 | + | |
| 226 | + post<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> { | |
| 227 | + return this.request({ ...config, method: 'POST' }, options); | |
| 228 | + } | |
| 229 | + | |
| 230 | + put<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> { | |
| 231 | + return this.request({ ...config, method: 'PUT' }, options); | |
| 232 | + } | |
| 233 | + | |
| 234 | + delete<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> { | |
| 235 | + return this.request({ ...config, method: 'DELETE' }, options); | |
| 236 | + } | |
| 237 | + | |
| 238 | + request<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> { | |
| 239 | + let conf: CreateAxiosOptions = cloneDeep(config); | |
| 240 | + const transform = this.getTransform(); | |
| 241 | + | |
| 242 | + const { requestOptions } = this.options; | |
| 243 | + | |
| 244 | + const opt: RequestOptions = Object.assign({}, requestOptions, options); | |
| 245 | + | |
| 246 | + const { beforeRequestHook, requestCatchHook, transformRequestHook } = transform || {}; | |
| 247 | + if (beforeRequestHook && isFunction(beforeRequestHook)) { | |
| 248 | + conf = beforeRequestHook(conf, opt); | |
| 249 | + } | |
| 250 | + conf.requestOptions = opt; | |
| 251 | + | |
| 252 | + conf = this.supportFormData(conf); | |
| 253 | + | |
| 254 | + return new Promise((resolve, reject) => { | |
| 255 | + this.axiosInstance | |
| 256 | + .request<any, AxiosResponse<Result>>(conf) | |
| 257 | + .then((res: AxiosResponse<Result>) => { | |
| 258 | + if (transformRequestHook && isFunction(transformRequestHook)) { | |
| 259 | + try { | |
| 260 | + const ret = transformRequestHook(res, opt); | |
| 261 | + resolve(ret); | |
| 262 | + } catch (err) { | |
| 263 | + reject(err || new Error('request error!')); | |
| 264 | + } | |
| 265 | + return; | |
| 266 | + } | |
| 267 | + resolve(res as unknown as Promise<T>); | |
| 268 | + }) | |
| 269 | + .catch((e: Error | AxiosError) => { | |
| 270 | + if (requestCatchHook && isFunction(requestCatchHook)) { | |
| 271 | + reject(requestCatchHook(e, opt)); | |
| 272 | + return; | |
| 273 | + } | |
| 274 | + if (axios.isAxiosError(e)) { | |
| 275 | + // rewrite error message from axios in here | |
| 276 | + } | |
| 277 | + reject(e); | |
| 278 | + }); | |
| 279 | + }); | |
| 280 | + } | |
| 281 | +} | ... | ... |
src/utils/external/http/axios/axiosCancel.ts
0 → 100644
| 1 | +import type { AxiosRequestConfig, Canceler } from 'axios'; | |
| 2 | +import axios from 'axios'; | |
| 3 | +import { isFunction } from '@/utils/external/is'; | |
| 4 | + | |
| 5 | +// Used to store the identification and cancellation function of each request | |
| 6 | +let pendingMap = new Map<string, Canceler>(); | |
| 7 | + | |
| 8 | +export const getPendingUrl = (config: AxiosRequestConfig) => [config.method, config.url].join('&'); | |
| 9 | + | |
| 10 | +export class AxiosCanceler { | |
| 11 | + /** | |
| 12 | + * Add request | |
| 13 | + * @param {Object} config | |
| 14 | + */ | |
| 15 | + addPending(config: AxiosRequestConfig) { | |
| 16 | + this.removePending(config); | |
| 17 | + const url = getPendingUrl(config); | |
| 18 | + config.cancelToken = | |
| 19 | + config.cancelToken || | |
| 20 | + new axios.CancelToken((cancel) => { | |
| 21 | + if (!pendingMap.has(url)) { | |
| 22 | + // If there is no current request in pending, add it | |
| 23 | + pendingMap.set(url, cancel); | |
| 24 | + } | |
| 25 | + }); | |
| 26 | + } | |
| 27 | + | |
| 28 | + /** | |
| 29 | + * @description: Clear all pending | |
| 30 | + */ | |
| 31 | + removeAllPending() { | |
| 32 | + pendingMap.forEach((cancel) => { | |
| 33 | + cancel && isFunction(cancel) && cancel(); | |
| 34 | + }); | |
| 35 | + pendingMap.clear(); | |
| 36 | + } | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * Removal request | |
| 40 | + * @param {Object} config | |
| 41 | + */ | |
| 42 | + removePending(config: AxiosRequestConfig) { | |
| 43 | + const url = getPendingUrl(config); | |
| 44 | + | |
| 45 | + if (pendingMap.has(url)) { | |
| 46 | + // If there is a current request identifier in pending, | |
| 47 | + // the current request needs to be cancelled and removed | |
| 48 | + const cancel = pendingMap.get(url); | |
| 49 | + cancel && cancel(url); | |
| 50 | + pendingMap.delete(url); | |
| 51 | + } | |
| 52 | + } | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * @description: reset | |
| 56 | + */ | |
| 57 | + reset(): void { | |
| 58 | + pendingMap = new Map<string, Canceler>(); | |
| 59 | + } | |
| 60 | +} | ... | ... |
| 1 | +/** | |
| 2 | + * Data processing class, can be configured according to the project | |
| 3 | + */ | |
| 4 | +import type { AxiosRequestConfig, AxiosResponse } from 'axios'; | |
| 5 | +import type { RequestOptions, Result } from '/#/external/axios'; | |
| 6 | + | |
| 7 | +export interface CreateAxiosOptions extends AxiosRequestConfig { | |
| 8 | + authenticationScheme?: string; | |
| 9 | + urlPrefix?: string; | |
| 10 | + transform?: AxiosTransform; | |
| 11 | + requestOptions?: RequestOptions; | |
| 12 | +} | |
| 13 | + | |
| 14 | +export abstract class AxiosTransform { | |
| 15 | + /** | |
| 16 | + * @description: Process configuration before request | |
| 17 | + * @description: Process configuration before request | |
| 18 | + */ | |
| 19 | + beforeRequestHook?: (config: AxiosRequestConfig, options: RequestOptions) => AxiosRequestConfig; | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * @description: Request successfully processed | |
| 23 | + */ | |
| 24 | + transformRequestHook?: (res: AxiosResponse<Result>, options: RequestOptions) => any; | |
| 25 | + | |
| 26 | + /** | |
| 27 | + * @description: 请求失败处理 | |
| 28 | + */ | |
| 29 | + requestCatchHook?: (e: Error, options: RequestOptions) => Promise<any>; | |
| 30 | + | |
| 31 | + /** | |
| 32 | + * @description: 请求之前的拦截器 | |
| 33 | + */ | |
| 34 | + requestInterceptors?: ( | |
| 35 | + config: AxiosRequestConfig, | |
| 36 | + options: CreateAxiosOptions | |
| 37 | + ) => AxiosRequestConfig; | |
| 38 | + | |
| 39 | + /** | |
| 40 | + * @description: 请求之后的拦截器 | |
| 41 | + */ | |
| 42 | + responseInterceptors?: (res: AxiosResponse<any>) => AxiosResponse<any>; | |
| 43 | + | |
| 44 | + /** | |
| 45 | + * @description: 请求之前的拦截器错误处理 | |
| 46 | + */ | |
| 47 | + requestInterceptorsCatch?: (error: Error) => void; | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * @description: 请求之后的拦截器错误处理 | |
| 51 | + */ | |
| 52 | + responseInterceptorsCatch?: (error: Error) => void; | |
| 53 | +} | ... | ... |
src/utils/external/http/axios/checkStatus.ts
0 → 100644
| 1 | +import type { ErrorMessageMode } from '/#/external/axios'; | |
| 2 | +import { useUserStoreWithOut } from '@/store/external/module/user'; | |
| 3 | +import { useI18n } from 'vue-i18n'; | |
| 4 | +import { useMessage } from 'naive-ui'; | |
| 5 | + | |
| 6 | +const { error } = useMessage() | |
| 7 | +export function checkStatus( | |
| 8 | + status: number, | |
| 9 | + msg: string, | |
| 10 | + errorMessageMode: ErrorMessageMode = 'message' | |
| 11 | +): void { | |
| 12 | + const { t } = useI18n(); | |
| 13 | + const userStore = useUserStoreWithOut(); | |
| 14 | + let errMessage = msg; | |
| 15 | + switch (status) { | |
| 16 | + case 400: | |
| 17 | + errMessage = `${msg}`; | |
| 18 | + break; | |
| 19 | + // 401: Not logged in | |
| 20 | + // Jump to the login page if not logged in, and carry the path of the current page | |
| 21 | + // Return to the current page after successful login. This step needs to be operated on the login page. | |
| 22 | + case 401: | |
| 23 | + errMessage = ''; | |
| 24 | + userStore.logout() | |
| 25 | + break; | |
| 26 | + case 403: | |
| 27 | + errMessage = '未授权'; | |
| 28 | + break; | |
| 29 | + // 404请求不存在 | |
| 30 | + case 404: | |
| 31 | + errMessage = '未找到该资源!'; | |
| 32 | + break; | |
| 33 | + case 405: | |
| 34 | + errMessage = '网络请求错误,请求方法未允许!'; | |
| 35 | + break; | |
| 36 | + case 408: | |
| 37 | + errMessage = '网络请求超时!'; | |
| 38 | + break; | |
| 39 | + case 500: | |
| 40 | + errMessage = '服务器错误,请联系管理员!'; | |
| 41 | + break; | |
| 42 | + case 501: | |
| 43 | + errMessage = '网络未实现!'; | |
| 44 | + break; | |
| 45 | + case 502: | |
| 46 | + errMessage = '网络错误!'; | |
| 47 | + break; | |
| 48 | + case 503: | |
| 49 | + errMessage = '服务不可用,服务器暂时过载或维护!'; | |
| 50 | + break; | |
| 51 | + case 504: | |
| 52 | + errMessage = '网络超时!'; | |
| 53 | + break; | |
| 54 | + case 505: | |
| 55 | + errMessage = 'http版本不支持该请求!'; | |
| 56 | + break; | |
| 57 | + default: | |
| 58 | + } | |
| 59 | + if (errMessage) { | |
| 60 | + if (errorMessageMode === 'message') { | |
| 61 | + error(errMessage); | |
| 62 | + } | |
| 63 | + } | |
| 64 | +} | ... | ... |
src/utils/external/http/axios/helper.ts
0 → 100644
| 1 | +import { isObject, isString } from '@/utils/external/is'; | |
| 2 | + | |
| 3 | +const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm'; | |
| 4 | + | |
| 5 | +export function joinTimestamp<T extends boolean>( | |
| 6 | + join: boolean, | |
| 7 | + restful: T | |
| 8 | +): T extends true ? string : object; | |
| 9 | + | |
| 10 | +export function joinTimestamp(join: boolean, restful = false): string | object { | |
| 11 | + if (!join) { | |
| 12 | + return restful ? '' : {}; | |
| 13 | + } | |
| 14 | + const now = new Date().getTime(); | |
| 15 | + if (restful) { | |
| 16 | + return `?_t=${now}`; | |
| 17 | + } | |
| 18 | + return { _t: now }; | |
| 19 | +} | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * @description: Format request parameter time | |
| 23 | + */ | |
| 24 | +export function formatRequestDate(params: Recordable) { | |
| 25 | + if (Object.prototype.toString.call(params) !== '[object Object]') { | |
| 26 | + return; | |
| 27 | + } | |
| 28 | + | |
| 29 | + for (const key in params) { | |
| 30 | + if (params[key] && params[key]._isAMomentObject) { | |
| 31 | + params[key] = params[key].format(DATE_TIME_FORMAT); | |
| 32 | + } | |
| 33 | + if (isString(key)) { | |
| 34 | + const value = params[key]; | |
| 35 | + if (value) { | |
| 36 | + try { | |
| 37 | + params[key] = isString(value) ? value.trim() : value; | |
| 38 | + } catch (error) { | |
| 39 | + throw new Error(error as string); | |
| 40 | + } | |
| 41 | + } | |
| 42 | + } | |
| 43 | + if (isObject(params[key])) { | |
| 44 | + formatRequestDate(params[key]); | |
| 45 | + } | |
| 46 | + } | |
| 47 | +} | ... | ... |
src/utils/external/http/axios/index.ts
0 → 100644
| 1 | +// axios配置 可自行根据项目进行更改,只需更改该文件即可,其他文件可以不动 | |
| 2 | +// The axios configuration can be changed according to the project, just change the file, other files can be left unchanged | |
| 3 | + | |
| 4 | +import type { AxiosResponse } from 'axios'; | |
| 5 | +import type { RequestOptions, Result } from '/#/external/axios'; | |
| 6 | +import type { AxiosTransform, CreateAxiosOptions } from './axiosTransform'; | |
| 7 | +import { VAxios } from './Axios'; | |
| 8 | +import { checkStatus } from './checkStatus'; | |
| 9 | +import { useGlobSetting } from '@/hooks/external/setting'; | |
| 10 | +import { RequestEnum, ContentTypeEnum } from '@/enums/external/httpEnum'; | |
| 11 | +import { isString } from '@/utils/external/is'; | |
| 12 | +import { getJwtToken } from '@/utils/external/auth'; | |
| 13 | +import { setObjToUrlParams, deepMerge } from '@/utils/external'; | |
| 14 | +import { joinTimestamp, formatRequestDate } from './helper'; | |
| 15 | +import { PageEnum } from '@/enums/external/pageEnum'; | |
| 16 | +import router from '@/router'; | |
| 17 | +import { useDialog } from 'naive-ui'; | |
| 18 | + | |
| 19 | +const globSetting = useGlobSetting(); | |
| 20 | +const urlPrefix = globSetting.urlPrefix; | |
| 21 | + | |
| 22 | +const { success, error } = useDialog() | |
| 23 | +/** | |
| 24 | + * @description: 数据处理,方便区分多种处理方式 | |
| 25 | + */ | |
| 26 | +const transform: AxiosTransform = { | |
| 27 | + /** | |
| 28 | + * @description: 处理请求数据。如果数据不是预期格式,可直接抛出错误 | |
| 29 | + */ | |
| 30 | + transformRequestHook: (res: AxiosResponse<Result>, options: RequestOptions) => { | |
| 31 | + const { isReturnNativeResponse } = options; | |
| 32 | + // 是否返回原生响应头 比如:需要获取响应头时使用该属性 | |
| 33 | + if (isReturnNativeResponse) { | |
| 34 | + return res; | |
| 35 | + } | |
| 36 | + return res.data; | |
| 37 | + }, | |
| 38 | + | |
| 39 | + // 请求之前处理config | |
| 40 | + beforeRequestHook: (config, options) => { | |
| 41 | + const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true } = options; | |
| 42 | + | |
| 43 | + if (joinPrefix) { | |
| 44 | + config.url = `${urlPrefix}${config.url}`; | |
| 45 | + } | |
| 46 | + | |
| 47 | + if (apiUrl && isString(apiUrl)) { | |
| 48 | + config.url = `${apiUrl}${config.url}`; | |
| 49 | + } | |
| 50 | + const params = config.params || {}; | |
| 51 | + const data = config.data || false; | |
| 52 | + formatDate && data && !isString(data) && formatRequestDate(data); | |
| 53 | + if (config.method?.toUpperCase() === RequestEnum.GET) { | |
| 54 | + if (!isString(params)) { | |
| 55 | + // 给 get 请求加上时间戳参数,避免从缓存中拿数据。 | |
| 56 | + config.params = Object.assign(params || {}, joinTimestamp(joinTime, false)); | |
| 57 | + } else { | |
| 58 | + // 兼容restful风格 | |
| 59 | + config.url = config.url + params + `${joinTimestamp(joinTime, true)}`; | |
| 60 | + config.params = undefined; | |
| 61 | + } | |
| 62 | + } else { | |
| 63 | + if (!isString(params)) { | |
| 64 | + formatDate && formatRequestDate(params); | |
| 65 | + if (Reflect.has(config, 'data') && config.data && Object.keys(config.data).length > 0) { | |
| 66 | + config.data = data; | |
| 67 | + config.params = params; | |
| 68 | + } else { | |
| 69 | + // 非GET请求如果没有提供data,则将params视为data | |
| 70 | + config.data = params; | |
| 71 | + config.params = undefined; | |
| 72 | + } | |
| 73 | + if (joinParamsToUrl) { | |
| 74 | + config.url = setObjToUrlParams( | |
| 75 | + config.url as string, | |
| 76 | + Object.assign({}, config.params, config.data) | |
| 77 | + ); | |
| 78 | + } | |
| 79 | + } else { | |
| 80 | + // 兼容restful风格 | |
| 81 | + config.url = config.url + params; | |
| 82 | + config.params = undefined; | |
| 83 | + } | |
| 84 | + } | |
| 85 | + return config; | |
| 86 | + }, | |
| 87 | + | |
| 88 | + /** | |
| 89 | + * @description: 请求拦截器处理 | |
| 90 | + */ | |
| 91 | + requestInterceptors: (config, options) => { | |
| 92 | + // 请求之前处理config | |
| 93 | + const token = getJwtToken(); | |
| 94 | + if (token && (config as Recordable)?.requestOptions?.withToken !== false) { | |
| 95 | + // jwt token | |
| 96 | + config.headers!['X-Authorization'] = options.authenticationScheme | |
| 97 | + ? `${options.authenticationScheme} ${token}` | |
| 98 | + : token as string; | |
| 99 | + } | |
| 100 | + return config; | |
| 101 | + }, | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * @description: 响应拦截器处理 | |
| 105 | + */ | |
| 106 | + responseInterceptors: (res: AxiosResponse<any>) => { | |
| 107 | + return res; | |
| 108 | + }, | |
| 109 | + | |
| 110 | + /** | |
| 111 | + * @description: 响应错误处理 | |
| 112 | + */ | |
| 113 | + responseInterceptorsCatch: (error: any) => { | |
| 114 | + | |
| 115 | + const { response, code, message, config } = error || {}; | |
| 116 | + | |
| 117 | + const errorMessageMode = config?.requestOptions?.errorMessageMode || 'none'; | |
| 118 | + const errorMsgIsObj = typeof response?.data === 'object'; | |
| 119 | + const msg: string = errorMsgIsObj | |
| 120 | + ? response?.data?.message || response?.data?.msg | |
| 121 | + : response?.data; | |
| 122 | + const err: string = error?.toString?.() ?? ''; | |
| 123 | + let errMessage = ''; | |
| 124 | + try { | |
| 125 | + if (response?.data?.status == '401' || response?.data?.message == '"Authentication failed"') { | |
| 126 | + window.localStorage.clear(); | |
| 127 | + window.sessionStorage.clear(); | |
| 128 | + router.push(PageEnum.BASE_HOME); | |
| 129 | + } | |
| 130 | + if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) { | |
| 131 | + errMessage = '接口请求超时,请刷新页面重试!' | |
| 132 | + } | |
| 133 | + if (err?.includes('Network Error')) { | |
| 134 | + errMessage = '网络异常,请检查您的网络连接时候正常!' | |
| 135 | + } | |
| 136 | + | |
| 137 | + if (errMessage) { | |
| 138 | + if (errorMessageMode === 'modal') { | |
| 139 | + error({ title: '错误提示', content: errMessage }) | |
| 140 | + } else if (errorMessageMode === 'message') { | |
| 141 | + error({ title: '错误提示', content: errMessage }) | |
| 142 | + } | |
| 143 | + return Promise.reject(error); | |
| 144 | + } | |
| 145 | + } catch (error: any) { | |
| 146 | + throw new Error(error); | |
| 147 | + } | |
| 148 | + checkStatus(error?.response?.status, msg, errorMessageMode); | |
| 149 | + return Promise.reject(response.data); | |
| 150 | + }, | |
| 151 | +}; | |
| 152 | + | |
| 153 | +function createAxios(opt?: Partial<CreateAxiosOptions>) { | |
| 154 | + return new VAxios( | |
| 155 | + deepMerge( | |
| 156 | + { | |
| 157 | + // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes | |
| 158 | + // authentication schemes,e.g: Bearer | |
| 159 | + // authenticationScheme: 'Bearer', | |
| 160 | + authenticationScheme: 'Bearer', | |
| 161 | + timeout: 10 * 1000, | |
| 162 | + // 基础接口地址 | |
| 163 | + // baseURL: globSetting.apiUrl, | |
| 164 | + // 接口可能会有通用的地址部分,可以统一抽取出来 | |
| 165 | + urlPrefix: urlPrefix, | |
| 166 | + headers: { 'Content-Type': ContentTypeEnum.JSON }, | |
| 167 | + // 如果是form-data格式 | |
| 168 | + // headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED }, | |
| 169 | + // 数据处理方式 | |
| 170 | + transform, | |
| 171 | + // 配置项,下面的选项都可以在独立的接口请求中覆盖 | |
| 172 | + requestOptions: { | |
| 173 | + // 默认将prefix 添加到url | |
| 174 | + joinPrefix: true, | |
| 175 | + // 是否返回原生响应头 比如:需要获取响应头时使用该属性 | |
| 176 | + isReturnNativeResponse: false, | |
| 177 | + // 需要对返回数据进行处理 | |
| 178 | + isTransformResponse: true, | |
| 179 | + // post请求的时候添加参数到url | |
| 180 | + joinParamsToUrl: false, | |
| 181 | + // 格式化提交参数时间 | |
| 182 | + formatDate: true, | |
| 183 | + // 消息提示类型 | |
| 184 | + errorMessageMode: 'message', | |
| 185 | + // 接口地址 | |
| 186 | + apiUrl: globSetting.apiUrl, | |
| 187 | + // 是否加入时间戳 | |
| 188 | + joinTime: true, | |
| 189 | + // 忽略重复请求 | |
| 190 | + ignoreCancelToken: true, | |
| 191 | + // 是否携带token | |
| 192 | + withToken: true, | |
| 193 | + }, | |
| 194 | + }, | |
| 195 | + opt || {} | |
| 196 | + ) | |
| 197 | + ); | |
| 198 | +} | |
| 199 | +export const defHttp = createAxios(); | |
| 200 | + | |
| 201 | +// other api url | |
| 202 | +export const otherHttp = createAxios({ | |
| 203 | + requestOptions: { | |
| 204 | + apiUrl: 'xxx', | |
| 205 | + }, | |
| 206 | +}); | ... | ... |
src/utils/external/index.ts
0 → 100644
| 1 | +import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router'; | |
| 2 | +import type { App, Component, Plugin } from 'vue'; | |
| 3 | + | |
| 4 | +import { unref } from 'vue'; | |
| 5 | +import { isObject } from '@/utils/external/is'; | |
| 6 | + | |
| 7 | +export const noop = () => { }; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * @description: Set ui mount node | |
| 11 | + */ | |
| 12 | +export function getPopupContainer(node?: HTMLElement): HTMLElement { | |
| 13 | + return (node?.parentNode as HTMLElement) ?? document.body; | |
| 14 | +} | |
| 15 | + | |
| 16 | +/** | |
| 17 | + * Add the object as a parameter to the URL | |
| 18 | + * @param baseUrl url | |
| 19 | + * @param obj | |
| 20 | + * @returns {string} | |
| 21 | + * eg: | |
| 22 | + * let obj = {a: '3', b: '4'} | |
| 23 | + * setObjToUrlParams('www.baidu.com', obj) | |
| 24 | + * ==>www.baidu.com?a=3&b=4 | |
| 25 | + */ | |
| 26 | +export function setObjToUrlParams(baseUrl: string, obj: any): string { | |
| 27 | + let parameters = ''; | |
| 28 | + for (const key in obj) { | |
| 29 | + parameters += key + '=' + encodeURIComponent(obj[key]) + '&'; | |
| 30 | + } | |
| 31 | + parameters = parameters.replace(/&$/, ''); | |
| 32 | + return /\?$/.test(baseUrl) ? baseUrl + parameters : baseUrl.replace(/\/?$/, '?') + parameters; | |
| 33 | +} | |
| 34 | + | |
| 35 | +export function deepMerge<T = any>(src: any = {}, target: any = {}): T { | |
| 36 | + let key: string; | |
| 37 | + for (key in target) { | |
| 38 | + src[key] = isObject(src[key]) ? deepMerge(src[key], target[key]) : (src[key] = target[key]); | |
| 39 | + } | |
| 40 | + return src; | |
| 41 | +} | |
| 42 | + | |
| 43 | +export function openWindow( | |
| 44 | + url: string, | |
| 45 | + opt?: { target?: TargetContext | string; noopener?: boolean; noreferrer?: boolean } | |
| 46 | +) { | |
| 47 | + const { target = '__blank', noopener = true, noreferrer = true } = opt || {}; | |
| 48 | + const feature: string[] = []; | |
| 49 | + | |
| 50 | + noopener && feature.push('noopener=yes'); | |
| 51 | + noreferrer && feature.push('noreferrer=yes'); | |
| 52 | + | |
| 53 | + window.open(url, target, feature.join(',')); | |
| 54 | +} | |
| 55 | + | |
| 56 | +// dynamic use hook props | |
| 57 | +export function getDynamicProps<T extends Recordable, U>(props: T): Partial<U> { | |
| 58 | + const ret: Recordable = {}; | |
| 59 | + | |
| 60 | + Object.keys(props).map((key) => { | |
| 61 | + ret[key] = unref((props as Recordable)[key]); | |
| 62 | + }); | |
| 63 | + | |
| 64 | + return ret as Partial<U>; | |
| 65 | +} | |
| 66 | + | |
| 67 | +export function getRawRoute(route: RouteLocationNormalized): RouteLocationNormalized { | |
| 68 | + if (!route) return route; | |
| 69 | + const { matched, ...opt } = route; | |
| 70 | + return { | |
| 71 | + ...opt, | |
| 72 | + matched: (matched | |
| 73 | + ? matched.map((item) => ({ | |
| 74 | + meta: item.meta, | |
| 75 | + name: item.name, | |
| 76 | + path: item.path, | |
| 77 | + })) | |
| 78 | + : undefined) as RouteRecordNormalized[], | |
| 79 | + }; | |
| 80 | +} | |
| 81 | + | |
| 82 | +export const withInstall = <T extends Component>(component: T, alias?: string) => { | |
| 83 | + const comp = component as any; | |
| 84 | + comp.install = (app: App) => { | |
| 85 | + app.component(comp.name || comp.displayName, component); | |
| 86 | + if (alias) { | |
| 87 | + app.config.globalProperties[alias] = component; | |
| 88 | + } | |
| 89 | + }; | |
| 90 | + return component as T & Plugin; | |
| 91 | +}; | ... | ... |
src/utils/external/is.ts
0 → 100644
| 1 | +const toString = Object.prototype.toString; | |
| 2 | + | |
| 3 | +export function is(val: unknown, type: string) { | |
| 4 | + return toString.call(val) === `[object ${type}]`; | |
| 5 | +} | |
| 6 | + | |
| 7 | +export function isDef<T = unknown>(val?: T): val is T { | |
| 8 | + return typeof val !== 'undefined'; | |
| 9 | +} | |
| 10 | + | |
| 11 | +export function isUnDef<T = unknown>(val?: T): val is T { | |
| 12 | + return !isDef(val); | |
| 13 | +} | |
| 14 | + | |
| 15 | +export function isObject(val: any): val is Record<any, any> { | |
| 16 | + return val !== null && is(val, 'Object'); | |
| 17 | +} | |
| 18 | + | |
| 19 | +export function isEmpty<T = unknown>(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<T = any>(val: unknown): val is Promise<T> { | |
| 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<any> { | |
| 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<any, any> { | |
| 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 | + /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/; | |
| 98 | + return reg.test(path); | |
| 99 | +} | ... | ... |
| ... | ... | @@ -20,6 +20,6 @@ |
| 20 | 20 | // "strictNullChecks": true, //不允许使用null |
| 21 | 21 | "noImplicitThis": true //不允许往this上面挂属性 |
| 22 | 22 | }, |
| 23 | - "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "types/**/*"], | |
| 23 | + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "types/**/*", "build/**/*"], | |
| 24 | 24 | "exclude": ["node_modules", "dist", "**/*.js"] |
| 25 | 25 | } | ... | ... |
types/external/axios.d.ts
0 → 100644
| 1 | +export type ErrorMessageMode = 'none' | 'modal' | 'message' | undefined; | |
| 2 | + | |
| 3 | +export interface RequestOptions { | |
| 4 | + // Splicing request parameters to url | |
| 5 | + joinParamsToUrl?: boolean; | |
| 6 | + // Format request parameter time | |
| 7 | + formatDate?: boolean; | |
| 8 | + // Whether to process the request result | |
| 9 | + isTransformResponse?: boolean; | |
| 10 | + // Whether to return native response headers | |
| 11 | + // For example: use this attribute when you need to get the response headers | |
| 12 | + isReturnNativeResponse?: boolean; | |
| 13 | + // Whether to join url | |
| 14 | + joinPrefix?: boolean; | |
| 15 | + // Interface address, use the default apiUrl if you leave it blank | |
| 16 | + apiUrl?: string; | |
| 17 | + // Error message prompt type | |
| 18 | + errorMessageMode?: ErrorMessageMode; | |
| 19 | + // Whether to add a timestamp | |
| 20 | + joinTime?: boolean; | |
| 21 | + ignoreCancelToken?: boolean; | |
| 22 | + // Whether to send token in header | |
| 23 | + withToken?: boolean; | |
| 24 | +} | |
| 25 | + | |
| 26 | +export interface Result<T = any> { | |
| 27 | + code: number; | |
| 28 | + type: 'success' | 'error' | 'warning'; | |
| 29 | + message: string; | |
| 30 | + result: T; | |
| 31 | +} | |
| 32 | + | |
| 33 | +// multipart/form-data: upload file | |
| 34 | +export interface UploadFileParams { | |
| 35 | + // Other parameters | |
| 36 | + data?: Recordable; | |
| 37 | + // File parameter interface field name | |
| 38 | + name?: string; | |
| 39 | + // file name | |
| 40 | + file: File | Blob; | |
| 41 | + // file name | |
| 42 | + filename?: string; | |
| 43 | + [key: string]: any; | |
| 44 | +} | |
| 45 | + | |
| 46 | +export interface PaginationResult<T = Recordable> { | |
| 47 | + items: T[]; | |
| 48 | + total: number; | |
| 49 | +} | ... | ... |
types/external/config.d.ts
0 → 100644
| 1 | +import { MenuTypeEnum, MenuModeEnum, TriggerEnum, MixSidebarTriggerEnum } from '/@/enums/menuEnum'; | |
| 2 | +import { | |
| 3 | + ContentEnum, | |
| 4 | + PermissionModeEnum, | |
| 5 | + ThemeEnum, | |
| 6 | + RouterTransitionEnum, | |
| 7 | + SettingButtonPositionEnum, | |
| 8 | + SessionTimeoutProcessingEnum, | |
| 9 | +} from '/@/enums/appEnum'; | |
| 10 | + | |
| 11 | +import { CacheTypeEnum } from '/@/enums/cacheEnum'; | |
| 12 | + | |
| 13 | +export type LocaleType = 'zh_CN' | 'en' | 'ru' | 'ja' | 'ko'; | |
| 14 | + | |
| 15 | +export interface MenuSetting { | |
| 16 | + bgColor: string; | |
| 17 | + fixed: boolean; | |
| 18 | + collapsed: boolean; | |
| 19 | + canDrag: boolean; | |
| 20 | + show: boolean; | |
| 21 | + hidden: boolean; | |
| 22 | + split: boolean; | |
| 23 | + menuWidth: number; | |
| 24 | + mode: MenuModeEnum; | |
| 25 | + type: MenuTypeEnum; | |
| 26 | + theme: ThemeEnum; | |
| 27 | + topMenuAlign: 'start' | 'center' | 'end'; | |
| 28 | + trigger: TriggerEnum; | |
| 29 | + accordion: boolean; | |
| 30 | + closeMixSidebarOnChange: boolean; | |
| 31 | + collapsedShowTitle: boolean; | |
| 32 | + mixSideTrigger: MixSidebarTriggerEnum; | |
| 33 | + mixSideFixed: boolean; | |
| 34 | +} | |
| 35 | + | |
| 36 | +export interface MultiTabsSetting { | |
| 37 | + cache: boolean; | |
| 38 | + show: boolean; | |
| 39 | + showQuick: boolean; | |
| 40 | + canDrag: boolean; | |
| 41 | + showRedo: boolean; | |
| 42 | + showFold: boolean; | |
| 43 | +} | |
| 44 | + | |
| 45 | +export interface HeaderSetting { | |
| 46 | + bgColor: string; | |
| 47 | + fixed: boolean; | |
| 48 | + show: boolean; | |
| 49 | + theme: ThemeEnum; | |
| 50 | + // Turn on full screen | |
| 51 | + showFullScreen: boolean; | |
| 52 | + // Whether to show the lock screen | |
| 53 | + useLockPage: boolean; | |
| 54 | + // Show document button | |
| 55 | + showDoc: boolean; | |
| 56 | + // Show message center button | |
| 57 | + showNotice: boolean; | |
| 58 | + showSearch: boolean; | |
| 59 | +} | |
| 60 | + | |
| 61 | +export interface LocaleSetting { | |
| 62 | + showPicker: boolean; | |
| 63 | + // Current language | |
| 64 | + locale: LocaleType; | |
| 65 | + // default language | |
| 66 | + fallback: LocaleType; | |
| 67 | + // available Locales | |
| 68 | + availableLocales: LocaleType[]; | |
| 69 | +} | |
| 70 | + | |
| 71 | +export interface TransitionSetting { | |
| 72 | + // Whether to open the page switching animation | |
| 73 | + enable: boolean; | |
| 74 | + // Route basic switching animation | |
| 75 | + basicTransition: RouterTransitionEnum; | |
| 76 | + // Whether to open page switching loading | |
| 77 | + openPageLoading: boolean; | |
| 78 | + // Whether to open the top progress bar | |
| 79 | + openNProgress: boolean; | |
| 80 | +} | |
| 81 | + | |
| 82 | +export interface ProjectConfig { | |
| 83 | + // Storage location of permission related information | |
| 84 | + permissionCacheType: CacheTypeEnum; | |
| 85 | + // Whether to show the configuration button | |
| 86 | + showSettingButton: boolean; | |
| 87 | + // Whether to show the theme switch button | |
| 88 | + showDarkModeToggle: boolean; | |
| 89 | + // Configure where the button is displayed | |
| 90 | + settingButtonPosition: SettingButtonPositionEnum; | |
| 91 | + // Permission mode | |
| 92 | + permissionMode: PermissionModeEnum; | |
| 93 | + // Session timeout processing | |
| 94 | + sessionTimeoutProcessing: SessionTimeoutProcessingEnum; | |
| 95 | + // Website gray mode, open for possible mourning dates | |
| 96 | + grayMode: boolean; | |
| 97 | + // Whether to turn on the color weak mode | |
| 98 | + colorWeak: boolean; | |
| 99 | + // Theme color | |
| 100 | + themeColor: string; | |
| 101 | + | |
| 102 | + // The main interface is displayed in full screen, the menu is not displayed, and the top | |
| 103 | + fullContent: boolean; | |
| 104 | + // content width | |
| 105 | + contentMode: ContentEnum; | |
| 106 | + // Whether to display the logo | |
| 107 | + showLogo: boolean; | |
| 108 | + // Whether to show the global footer | |
| 109 | + showFooter: boolean; | |
| 110 | + // menuType: MenuTypeEnum; | |
| 111 | + headerSetting: HeaderSetting; | |
| 112 | + // menuSetting | |
| 113 | + menuSetting: MenuSetting; | |
| 114 | + // Multi-tab settings | |
| 115 | + multiTabsSetting: MultiTabsSetting; | |
| 116 | + // Animation configuration | |
| 117 | + transitionSetting: TransitionSetting; | |
| 118 | + // pageLayout whether to enable keep-alive | |
| 119 | + openKeepAlive: boolean; | |
| 120 | + // Lock screen time | |
| 121 | + lockTime: number; | |
| 122 | + // Show breadcrumbs | |
| 123 | + showBreadCrumb: boolean; | |
| 124 | + // Show breadcrumb icon | |
| 125 | + showBreadCrumbIcon: boolean; | |
| 126 | + // Use error-handler-plugin | |
| 127 | + useErrorHandle: boolean; | |
| 128 | + // Whether to open back to top | |
| 129 | + useOpenBackTop: boolean; | |
| 130 | + // Is it possible to embed iframe pages | |
| 131 | + canEmbedIFramePage: boolean; | |
| 132 | + // Whether to delete unclosed messages and notify when switching the interface | |
| 133 | + closeMessageOnSwitch: boolean; | |
| 134 | + // Whether to cancel the http request that has been sent but not responded when switching the interface. | |
| 135 | + removeAllHttpPending: boolean; | |
| 136 | +} | |
| 137 | + | |
| 138 | +export interface GlobConfig { | |
| 139 | + // Site title | |
| 140 | + title: string; | |
| 141 | + // Service interface url | |
| 142 | + apiUrl: string; | |
| 143 | + // Upload url | |
| 144 | + uploadUrl?: string; | |
| 145 | + // Service interface url prefix | |
| 146 | + urlPrefix?: string; | |
| 147 | + // Project abbreviation | |
| 148 | + shortName: string; | |
| 149 | + // configuration center proxy prefix | |
| 150 | + configurationPrefix: string; | |
| 151 | + // socket url | |
| 152 | + socketUrl: string; | |
| 153 | + // alarm notify alarm duration | |
| 154 | + alarmNotifyDuration: string; | |
| 155 | + // alarm notify polling interval | |
| 156 | + alarmPollingInterval: string; | |
| 157 | + // upgrade your http policy to https | |
| 158 | + securityPolicy: string; | |
| 159 | +} | |
| 160 | +export interface GlobEnvConfig { | |
| 161 | + // Site title | |
| 162 | + VITE_GLOB_APP_TITLE: string; | |
| 163 | + // Service interface url | |
| 164 | + VITE_GLOB_API_URL: string; | |
| 165 | + // Service interface url prefix | |
| 166 | + VITE_GLOB_API_URL_PREFIX?: string; | |
| 167 | + // Project abbreviation | |
| 168 | + VITE_GLOB_APP_SHORT_NAME: string; | |
| 169 | + // Upload url | |
| 170 | + VITE_GLOB_UPLOAD_URL?: string; | |
| 171 | + // configuration | |
| 172 | + VITE_GLOB_CONFIGURATION: string; | |
| 173 | + // socket | |
| 174 | + VITE_GLOB_WEB_SOCKET: string; | |
| 175 | + // force transform http to https | |
| 176 | + VITE_GLOB_CONTENT_SECURITY_POLICY: string; | |
| 177 | + // notify polling interval time | |
| 178 | + VITE_GLOB_ALARM_NOTIFY_POLLING_INTERVAL_TIME: string; | |
| 179 | + // notify duration | |
| 180 | + VITE_GLOB_ALARM_NOTIFY_DURATION: string; | |
| 181 | +} | ... | ... |
types/external/global.d.ts
0 → 100644
| 1 | +import type { | |
| 2 | + ComponentRenderProxy, | |
| 3 | + VNode, | |
| 4 | + VNodeChild, | |
| 5 | + ComponentPublicInstance, | |
| 6 | + FunctionalComponent, | |
| 7 | + PropType as VuePropType, | |
| 8 | +} from 'vue'; | |
| 9 | + | |
| 10 | +declare global { | |
| 11 | + const __APP_INFO__: { | |
| 12 | + pkg: { | |
| 13 | + name: string; | |
| 14 | + version: string; | |
| 15 | + dependencies: Recordable<string>; | |
| 16 | + devDependencies: Recordable<string>; | |
| 17 | + }; | |
| 18 | + lastBuildTime: string; | |
| 19 | + }; | |
| 20 | + // declare interface Window { | |
| 21 | + // // Global vue app instance | |
| 22 | + // __APP__: App<Element>; | |
| 23 | + // } | |
| 24 | + | |
| 25 | + // vue | |
| 26 | + declare type PropType<T> = VuePropType<T>; | |
| 27 | + declare type VueNode = VNodeChild | JSX.Element; | |
| 28 | + | |
| 29 | + export type Writable<T> = { | |
| 30 | + -readonly [P in keyof T]: T[P]; | |
| 31 | + }; | |
| 32 | + | |
| 33 | + declare type Nullable<T> = T | null; | |
| 34 | + declare type NonNullable<T> = T extends null | undefined ? never : T; | |
| 35 | + declare type Recordable<T = any> = Record<string, T>; | |
| 36 | + declare type ReadonlyRecordable<T = any> = { | |
| 37 | + readonly [key: string]: T; | |
| 38 | + }; | |
| 39 | + declare type Indexable<T = any> = { | |
| 40 | + [key: string]: T; | |
| 41 | + }; | |
| 42 | + declare type DeepPartial<T> = { | |
| 43 | + [P in keyof T]?: DeepPartial<T[P]>; | |
| 44 | + }; | |
| 45 | + declare type TimeoutHandle = ReturnType<typeof setTimeout>; | |
| 46 | + declare type IntervalHandle = ReturnType<typeof setInterval>; | |
| 47 | + | |
| 48 | + declare interface ChangeEvent extends Event { | |
| 49 | + target: HTMLInputElement; | |
| 50 | + } | |
| 51 | + | |
| 52 | + declare interface WheelEvent { | |
| 53 | + path?: EventTarget[]; | |
| 54 | + } | |
| 55 | + interface ImportMetaEnv extends ViteEnv { | |
| 56 | + __: unknown; | |
| 57 | + } | |
| 58 | + | |
| 59 | + declare interface ViteEnv { | |
| 60 | + VITE_PORT: number; | |
| 61 | + VITE_GLOB_USE_MOCK: boolean; | |
| 62 | + VITE_USE_PWA: boolean; | |
| 63 | + VITE_GLOB_PUBLIC_PATH: string; | |
| 64 | + VITE_PROXY: [string, string][]; | |
| 65 | + VITE_GLOB_APP_TITLE: string; | |
| 66 | + VITE_GLOB_APP_SHORT_NAME: string; | |
| 67 | + VITE_USE_CDN: boolean; | |
| 68 | + VITE_GLOB_DROP_CONSOLE: boolean; | |
| 69 | + VITE_GLOB_BUILD_COMPRESS: 'gzip' | 'brotli' | 'none'; | |
| 70 | + VITE_GLOB_BUILD_COMPRESS_DELETE_ORIGIN_FILE: boolean; | |
| 71 | + VITE_LEGACY: boolean; | |
| 72 | + VITE_GLOB_USE_IMAGEMIN: boolean; | |
| 73 | + VITE_GENERATE_UI: string; | |
| 74 | + VITE_GLOB_CONTENT_SECURITY_POLICY: boolean; | |
| 75 | + VITE_GLOB_ALARM_NOTIFY_POLLING_INTERVAL_TIME: number; | |
| 76 | + VITE_GLOB_ALARM_NOTIFY_DURATION: number; | |
| 77 | + } | |
| 78 | + | |
| 79 | + declare function parseInt(s: string | number, radix?: number): number; | |
| 80 | + | |
| 81 | + declare function parseFloat(string: string | number): number; | |
| 82 | + | |
| 83 | + namespace JSX { | |
| 84 | + // tslint:disable no-empty-interface | |
| 85 | + type Element = VNode; | |
| 86 | + // tslint:disable no-empty-interface | |
| 87 | + type ElementClass = ComponentRenderProxy; | |
| 88 | + interface ElementAttributesProperty { | |
| 89 | + $props: any; | |
| 90 | + } | |
| 91 | + interface IntrinsicElements { | |
| 92 | + [elem: string]: any; | |
| 93 | + } | |
| 94 | + interface IntrinsicAttributes { | |
| 95 | + [elem: string]: any; | |
| 96 | + } | |
| 97 | + } | |
| 98 | +} | |
| 99 | + | |
| 100 | +declare module 'vue' { | |
| 101 | + export type JSXComponent<Props = any> = | |
| 102 | + | { new (): ComponentPublicInstance<Props> } | |
| 103 | + | FunctionalComponent<Props>; | |
| 104 | +} | ... | ... |
types/external/index.d.ts
0 → 100644
| 1 | +declare interface Fn<T = any, R = T> { | |
| 2 | + (...arg: T[]): R; | |
| 3 | +} | |
| 4 | + | |
| 5 | +declare interface PromiseFn<T = any, R = T> { | |
| 6 | + (...arg: T[]): Promise<R>; | |
| 7 | +} | |
| 8 | + | |
| 9 | +declare type RefType<T> = T | null; | |
| 10 | + | |
| 11 | +declare type LabelValueOptions = { | |
| 12 | + label: string; | |
| 13 | + value: any; | |
| 14 | + [key: string]: string | number | boolean; | |
| 15 | +}[]; | |
| 16 | + | |
| 17 | +declare type EmitType = (event: string, ...args: any[]) => void; | |
| 18 | + | |
| 19 | +declare type TargetContext = '_self' | '_blank'; | |
| 20 | + | |
| 21 | +declare interface ComponentElRef<T extends HTMLElement = HTMLDivElement> { | |
| 22 | + $el: T; | |
| 23 | +} | |
| 24 | + | |
| 25 | +declare type ComponentRef<T extends HTMLElement = HTMLDivElement> = ComponentElRef<T> | null; | |
| 26 | + | |
| 27 | +declare type ElRef<T extends HTMLElement = HTMLDivElement> = Nullable<T>; | ... | ... |
types/external/store.d.ts
0 → 100644
| 1 | +import { ErrorTypeEnum } from '/@/enums/exceptionEnum'; | |
| 2 | +import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum'; | |
| 3 | +import { PlainRoleInfo } from '/@/api/sys/model/userModel'; | |
| 4 | + | |
| 5 | +// Lock screen information | |
| 6 | +export interface LockInfo { | |
| 7 | + // Password required | |
| 8 | + pwd?: string | undefined; | |
| 9 | + // Is it locked? | |
| 10 | + isLock?: boolean; | |
| 11 | +} | |
| 12 | + | |
| 13 | +// Error-log information | |
| 14 | +export interface ErrorLogInfo { | |
| 15 | + // Type of error | |
| 16 | + type: ErrorTypeEnum; | |
| 17 | + // Error file | |
| 18 | + file: string; | |
| 19 | + // Error name | |
| 20 | + name?: string; | |
| 21 | + // Error message | |
| 22 | + message: string; | |
| 23 | + // Error stack | |
| 24 | + stack?: string; | |
| 25 | + // Error detail | |
| 26 | + detail: string; | |
| 27 | + // Error url | |
| 28 | + url: string; | |
| 29 | + // Error time | |
| 30 | + time?: string; | |
| 31 | +} | |
| 32 | + | |
| 33 | +export interface UserInfo { | |
| 34 | + userId?: string | number; | |
| 35 | + username?: string; | |
| 36 | + realName?: string; | |
| 37 | + avatar?: string; | |
| 38 | + homePath?: string; | |
| 39 | + tenantCode?: string; | |
| 40 | + tenantName?: string; | |
| 41 | + roles?: string[]; | |
| 42 | + plainRoles?: PlainRoleInfo[]; | |
| 43 | + phoneNumber?: string; | |
| 44 | + email?: string; | |
| 45 | +} | |
| 46 | + | |
| 47 | +export interface BeforeMiniState { | |
| 48 | + menuCollapsed?: boolean; | |
| 49 | + menuSplit?: boolean; | |
| 50 | + menuMode?: MenuModeEnum; | |
| 51 | + menuType?: MenuTypeEnum; | |
| 52 | +} | |
| 53 | + | |
| 54 | +export interface UserUpdateInfo { | |
| 55 | + activateToken?: string; | |
| 56 | + avatar?: string; | |
| 57 | + createTime?: string; | |
| 58 | + creator?: string; | |
| 59 | + email?: string; | |
| 60 | + enabled?: true; | |
| 61 | + hasPassword?: false; | |
| 62 | + id?: string; | |
| 63 | + level?: 2; | |
| 64 | + password?: string; | |
| 65 | + phoneNumber?: string; | |
| 66 | + realName?: string; | |
| 67 | + tenantId?: string; | |
| 68 | + updateTime?: string; | |
| 69 | + updater?: string; | |
| 70 | + username?: string; | |
| 71 | +} | ... | ... |
| 1 | 1 | /// <reference types="vite/client" /> |
| 2 | 2 | |
| 3 | -interface ImportMetaEnv { | |
| 3 | + | |
| 4 | +declare interface GlobEnvConfig { | |
| 4 | 5 | // 标题 |
| 5 | 6 | VITE_GLOB_APP_TITLE: string; |
| 7 | + // 公共路径 | |
| 8 | + VITE_GLOB_PUBLIC_PATH: string | |
| 9 | + // 代理地址 | |
| 10 | + VITE_GLOB_PROXY: [string, string][] | |
| 11 | + // 内容安全协议 | |
| 12 | + VITE_GLOB_CONTENT_SECURITY_POLICY: boolean | |
| 13 | + | |
| 14 | + VITE_GLOB_APP_SHORT_NAME: string | |
| 15 | +} | |
| 16 | + | |
| 17 | + | |
| 18 | +declare type GlobConfig = { | |
| 19 | + | |
| 20 | +} | |
| 21 | + | |
| 22 | +declare interface ViteEnv extends GlobEnvConfig { | |
| 6 | 23 | // 端口 |
| 7 | 24 | VITE_DEV_PORT: string; |
| 8 | 25 | // 开发地址 |
| 9 | 26 | VITE_DEV_PATH: string |
| 10 | 27 | // 生产地址 |
| 11 | 28 | VITE_PRO_PATH: string |
| 12 | -} | |
| \ No newline at end of file | ||
| 29 | +} | |
| 30 | + | |
| 31 | +interface ImportMetaEnv extends ViteEnv { | |
| 32 | +} | |
| 33 | + | ... | ... |
| 1 | -import { defineConfig } from 'vite' | |
| 1 | +import { defineConfig, loadEnv } from 'vite' | |
| 2 | 2 | import vue from '@vitejs/plugin-vue' |
| 3 | 3 | import { resolve } from 'path' |
| 4 | 4 | import { OUTPUT_DIR, brotliSize, chunkSizeWarningLimit, terserOptions, rollupOptions } from './build/constant' |
| 5 | 5 | import viteCompression from 'vite-plugin-compression' |
| 6 | 6 | import { viteMockServe } from 'vite-plugin-mock' |
| 7 | 7 | import monacoEditorPlugin from 'vite-plugin-monaco-editor' |
| 8 | +import { createProxy } from './build/external/vite/proxy' | |
| 9 | +import { parseEnv } from './build/external/utils' | |
| 10 | +import { GenerateBuildConfig } from './build/external/globConfig' | |
| 8 | 11 | |
| 9 | 12 | function pathResolve(dir: string) { |
| 10 | 13 | return resolve(process.cwd(), '.', dir) |
| 11 | 14 | } |
| 12 | 15 | |
| 13 | -export default defineConfig({ | |
| 14 | - base: '/', | |
| 15 | - // 路径重定向 | |
| 16 | - resolve: { | |
| 17 | - alias: [ | |
| 18 | - { | |
| 19 | - find: /\/#\//, | |
| 20 | - replacement: pathResolve('types') | |
| 21 | - }, | |
| 22 | - { | |
| 23 | - find: '@', | |
| 24 | - replacement: pathResolve('src') | |
| 25 | - }, | |
| 26 | - { | |
| 27 | - find: 'vue-i18n', | |
| 28 | - replacement: 'vue-i18n/dist/vue-i18n.cjs.js', //解决i8n警告 | |
| 16 | +export default defineConfig(({ mode, command }) => { | |
| 17 | + | |
| 18 | + const root = process.cwd() | |
| 19 | + | |
| 20 | + const env = loadEnv(mode, root) | |
| 21 | + | |
| 22 | + const viteEnv = parseEnv(env) | |
| 23 | + | |
| 24 | + const isBuild = command === 'build' | |
| 25 | + | |
| 26 | + return { | |
| 27 | + base: '/', | |
| 28 | + // 路径重定向 | |
| 29 | + resolve: { | |
| 30 | + alias: [ | |
| 31 | + { | |
| 32 | + find: /\/#\//, | |
| 33 | + replacement: pathResolve('types') | |
| 34 | + }, | |
| 35 | + { | |
| 36 | + find: '@', | |
| 37 | + replacement: pathResolve('src') | |
| 38 | + }, | |
| 39 | + { | |
| 40 | + find: 'vue-i18n', | |
| 41 | + replacement: 'vue-i18n/dist/vue-i18n.cjs.js', //解决i8n警告 | |
| 42 | + } | |
| 43 | + ], | |
| 44 | + dedupe: ['vue'] | |
| 45 | + }, | |
| 46 | + // 全局 css 注册 | |
| 47 | + css: { | |
| 48 | + preprocessorOptions: { | |
| 49 | + scss: { | |
| 50 | + javascriptEnabled: true, | |
| 51 | + additionalData: `@import "src/styles/common/style.scss";` | |
| 52 | + } | |
| 29 | 53 | } |
| 54 | + }, | |
| 55 | + plugins: [ | |
| 56 | + vue(), | |
| 57 | + monacoEditorPlugin({ | |
| 58 | + languageWorkers: ['editorWorkerService', 'typescript', 'json', 'html'] | |
| 59 | + }), | |
| 60 | + viteMockServe({ | |
| 61 | + mockPath: '/src/api/mock', | |
| 62 | + // 开发打包开关 | |
| 63 | + localEnabled: true, | |
| 64 | + // 生产打包开关 | |
| 65 | + prodEnabled: true, | |
| 66 | + // 打开后,可以读取 ts 文件模块。 请注意,打开后将无法监视.js 文件 | |
| 67 | + supportTs: true, | |
| 68 | + // 监视文件更改 | |
| 69 | + watchFiles: true | |
| 70 | + }), | |
| 71 | + // 压缩 | |
| 72 | + viteCompression({ | |
| 73 | + verbose: true, | |
| 74 | + disable: false, | |
| 75 | + threshold: 10240, | |
| 76 | + algorithm: 'gzip', | |
| 77 | + ext: '.gz' | |
| 78 | + }), | |
| 79 | + GenerateBuildConfig(viteEnv) | |
| 30 | 80 | ], |
| 31 | - dedupe: ['vue'] | |
| 32 | - }, | |
| 33 | - // 全局 css 注册 | |
| 34 | - css: { | |
| 35 | - preprocessorOptions: { | |
| 36 | - scss: { | |
| 37 | - javascriptEnabled: true, | |
| 38 | - additionalData: `@import "src/styles/common/style.scss";` | |
| 39 | - } | |
| 81 | + build: { | |
| 82 | + target: 'es2015', | |
| 83 | + outDir: OUTPUT_DIR, | |
| 84 | + // minify: 'terser', // 如果需要用terser混淆,可打开这两行 | |
| 85 | + // terserOptions: terserOptions, | |
| 86 | + rollupOptions: rollupOptions, | |
| 87 | + brotliSize: brotliSize, | |
| 88 | + chunkSizeWarningLimit: chunkSizeWarningLimit | |
| 89 | + }, | |
| 90 | + server: { | |
| 91 | + proxy: createProxy(viteEnv) | |
| 40 | 92 | } |
| 41 | - }, | |
| 42 | - plugins: [ | |
| 43 | - vue(), | |
| 44 | - monacoEditorPlugin({ | |
| 45 | - languageWorkers: ['editorWorkerService', 'typescript', 'json', 'html'] | |
| 46 | - }), | |
| 47 | - viteMockServe({ | |
| 48 | - mockPath: '/src/api/mock', | |
| 49 | - // 开发打包开关 | |
| 50 | - localEnabled: true, | |
| 51 | - // 生产打包开关 | |
| 52 | - prodEnabled: true, | |
| 53 | - // 打开后,可以读取 ts 文件模块。 请注意,打开后将无法监视.js 文件 | |
| 54 | - supportTs: true, | |
| 55 | - // 监视文件更改 | |
| 56 | - watchFiles: true | |
| 57 | - }), | |
| 58 | - // 压缩 | |
| 59 | - viteCompression({ | |
| 60 | - verbose: true, | |
| 61 | - disable: false, | |
| 62 | - threshold: 10240, | |
| 63 | - algorithm: 'gzip', | |
| 64 | - ext: '.gz' | |
| 65 | - }) | |
| 66 | - ], | |
| 67 | - build: { | |
| 68 | - target: 'es2015', | |
| 69 | - outDir: OUTPUT_DIR, | |
| 70 | - // minify: 'terser', // 如果需要用terser混淆,可打开这两行 | |
| 71 | - // terserOptions: terserOptions, | |
| 72 | - rollupOptions: rollupOptions, | |
| 73 | - brotliSize: brotliSize, | |
| 74 | - chunkSizeWarningLimit: chunkSizeWarningLimit | |
| 75 | 93 | } |
| 76 | -}) | |
| 94 | +} | |
| 95 | +) | ... | ... |