@gx-design-vue/create-gx-cli 0.0.1 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- package/package.json +1 -1
- package/src/cli.js +23 -14
- package/template-mobile-ts/README.md +1 -16
- package/template-mobile-ts/build/plugin/index.ts +13 -1
- package/template-mobile-ts/build/script/postBuild.ts +15 -0
- package/template-mobile-ts/package.json +12 -5
- package/template-mobile-ts/postcss.config.js +5 -8
- package/template-mobile-ts/src/components/PageContainer/index.tsx +1 -0
- package/template-mobile-ts/src/core/vant-design/index.ts +0 -5
- package/template-mobile-ts/src/hooks/web/usePageLoading.ts +5 -8
- package/template-mobile-ts/src/main.ts +3 -1
- package/template-mobile-ts/src/{views → pages}/home.vue +1 -12
- package/template-mobile-ts/src/router/index.ts +3 -4
- package/template-mobile-ts/src/router/routes.ts +1 -1
- package/template-mobile-ts/src/settings/index.ts +10 -0
- package/template-mobile-ts/src/store/modules/global.ts +1 -4
- package/template-mobile-ts/src/utils/cryptoJS.ts +31 -17
- package/template-mobile-ts/src/utils/{index.ts → env.ts} +1 -1
- package/template-mobile-ts/src/utils/request/XHR.ts +131 -0
- package/template-mobile-ts/src/utils/request/axiosCancel.ts +60 -0
- package/template-mobile-ts/src/utils/request/checkStatus.ts +11 -0
- package/template-mobile-ts/src/utils/request/index.ts +143 -0
- package/template-mobile-ts/src/utils/request/typings.ts +114 -0
- package/template-mobile-ts/src/utils/storage.ts +191 -0
- package/template-mobile-ts/src/utils/validate.ts +0 -264
- package/template-mobile-ts/types/global.d.ts +16 -0
- package/template-mobile-ts/vite.config.ts +16 -2
- package/template-mobile-ts/pnpm-lock.yaml +0 -3890
- package/template-mobile-ts/src/utils/request.ts +0 -105
- package/template-vue-ts/.vscode/extensions.json +0 -3
- package/template-vue-ts/README.md +0 -18
- package/template-vue-ts/index.html +0 -13
- package/template-vue-ts/package.json +0 -20
- package/template-vue-ts/public/vite.svg +0 -1
- package/template-vue-ts/src/App.vue +0 -30
- package/template-vue-ts/src/assets/vue.svg +0 -1
- package/template-vue-ts/src/components/HelloWorld.vue +0 -38
- package/template-vue-ts/src/main.ts +0 -5
- package/template-vue-ts/src/style.css +0 -81
- package/template-vue-ts/src/vite-env.d.ts +0 -1
- package/template-vue-ts/tsconfig.json +0 -18
- package/template-vue-ts/tsconfig.node.json +0 -9
- package/template-vue-ts/vite.config.ts +0 -7
package/package.json
CHANGED
package/src/cli.js
CHANGED
@@ -1,24 +1,28 @@
|
|
1
|
+
import fs from 'fs'
|
2
|
+
import path from 'path'
|
1
3
|
import minimist from 'minimist'
|
2
4
|
import prompts from 'prompts'
|
3
|
-
import {
|
5
|
+
import { yellow, reset } from 'kolorist'
|
4
6
|
import { createProject } from './main'
|
5
7
|
|
6
8
|
const defaultTargetDir = 'gx-cli-project'
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
color: yellow
|
12
|
-
},
|
13
|
-
{
|
14
|
-
name: 'mobile',
|
15
|
-
color: blue
|
16
|
-
}
|
17
|
-
]
|
10
|
+
function getTemplate() {
|
11
|
+
const templateList = []
|
12
|
+
const files = fs.readdirSync(path.join(process.cwd(), '../'))
|
18
13
|
|
19
|
-
const
|
20
|
-
|
21
|
-
|
14
|
+
for (const file of files) {
|
15
|
+
if (file.indexOf('template') >= 0) {
|
16
|
+
templateList.push(file)
|
17
|
+
}
|
18
|
+
}
|
19
|
+
return templateList.map((el) => {
|
20
|
+
return {
|
21
|
+
name: el.split('-')[1],
|
22
|
+
color: yellow
|
23
|
+
}
|
24
|
+
})
|
25
|
+
}
|
22
26
|
|
23
27
|
function formatTargetDir(targetDir) {
|
24
28
|
return targetDir ? targetDir.trim().replace(/\/+$/g, '') : ''
|
@@ -35,6 +39,11 @@ function parseArgumentsIntoOptions() {
|
|
35
39
|
}
|
36
40
|
|
37
41
|
async function promptForMissingOptions(options) {
|
42
|
+
const FRAMEWORKS = getTemplate()
|
43
|
+
|
44
|
+
const TEMPLATES = FRAMEWORKS.map(
|
45
|
+
(f) => (f.variants && f.variants.map((v) => v.name)) || [f.name]
|
46
|
+
).reduce((a, b) => a.concat(b), [])
|
38
47
|
const answers = await prompts([
|
39
48
|
{
|
40
49
|
type: options.projectName ? null : 'text',
|
@@ -1,16 +1 @@
|
|
1
|
-
# Vue 3 + TypeScript + Vite
|
2
|
-
|
3
|
-
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
4
|
-
|
5
|
-
## Recommended IDE Setup
|
6
|
-
|
7
|
-
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar)
|
8
|
-
|
9
|
-
## Type Support For `.vue` Imports in TS
|
10
|
-
|
11
|
-
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates. However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can enable Volar's Take Over mode by following these steps:
|
12
|
-
|
13
|
-
1. Run `Extensions: Show Built-in Extensions` from VS Code's command palette, look for `TypeScript and JavaScript Language Features`, then right click and select `Disable (Workspace)`. By default, Take Over mode will enable itself if the default TypeScript extension is disabled.
|
14
|
-
2. Reload the VS Code window by running `Developer: Reload Window` from the command palette.
|
15
|
-
|
16
|
-
You can learn more about Take Over mode [here](https://github.com/johnsoncodehk/volar/discussions/471).
|
1
|
+
# Vue 3 + TypeScript + Vite + Vant
|
@@ -4,13 +4,16 @@ import vue from '@vitejs/plugin-vue'
|
|
4
4
|
import vueJsx from '@vitejs/plugin-vue-jsx'
|
5
5
|
|
6
6
|
import vueSetupExtend from 'vite-plugin-vue-setup-extend'
|
7
|
+
|
8
|
+
import { presetAttributify, presetUno, transformerDirectives } from 'unocss'
|
9
|
+
import Unocss from 'unocss/vite'
|
10
|
+
|
7
11
|
import { configHtmlPlugin } from './html'
|
8
12
|
import { configMockPlugin } from './mock'
|
9
13
|
import { createAutoImport } from './autoImport'
|
10
14
|
|
11
15
|
export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
|
12
16
|
const {
|
13
|
-
VITE_USE_V_CONSOLE,
|
14
17
|
VITE_USE_MOCK
|
15
18
|
} = viteEnv
|
16
19
|
|
@@ -21,6 +24,15 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
|
|
21
24
|
vueJsx()
|
22
25
|
]
|
23
26
|
|
27
|
+
// unocss
|
28
|
+
vitePlugins.push(Unocss({
|
29
|
+
presets: [
|
30
|
+
presetAttributify(),
|
31
|
+
presetUno()
|
32
|
+
],
|
33
|
+
transformers: [ transformerDirectives() ]
|
34
|
+
}))
|
35
|
+
|
24
36
|
// vite-plugin-vue-setup-extend
|
25
37
|
vitePlugins.push(vueSetupExtend())
|
26
38
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
// #!/usr/bin/env node
|
2
|
+
import chalk from 'chalk'
|
3
|
+
import { wrapperEnv, getEnvConfig } from '../utils'
|
4
|
+
|
5
|
+
import pkg from '../../package.json'
|
6
|
+
|
7
|
+
export const runBuild = async () => {
|
8
|
+
try {
|
9
|
+
console.log(`✨ ${chalk.cyan(`[${pkg.name}]`)}` + ' - build successfully!')
|
10
|
+
} catch (error) {
|
11
|
+
console.log(chalk.red('vite build error:\n' + error))
|
12
|
+
process.exit(1)
|
13
|
+
}
|
14
|
+
}
|
15
|
+
runBuild()
|
@@ -1,6 +1,5 @@
|
|
1
1
|
{
|
2
|
-
"name": "
|
3
|
-
"private": true,
|
2
|
+
"name": "gx-mobile-cli",
|
4
3
|
"version": "0.0.0",
|
5
4
|
"scripts": {
|
6
5
|
"dev": "vite",
|
@@ -9,17 +8,25 @@
|
|
9
8
|
"preview": "vite preview"
|
10
9
|
},
|
11
10
|
"dependencies": {
|
11
|
+
"@gx-design-vue/pro-hooks": "^0.0.8",
|
12
|
+
"@gx-design-vue/pro-utils": "^0.0.33",
|
13
|
+
"@vueuse/core": "^9.10.0",
|
14
|
+
"@vueuse/shared": "^9.10.0",
|
12
15
|
"axios": "^1.1.3",
|
13
16
|
"crypto-js": "^4.1.1",
|
14
17
|
"dayjs": "^1.11.6",
|
18
|
+
"lodash-es": "^4.17.21",
|
19
|
+
"lodash-unified": "^1.0.3",
|
15
20
|
"mockjs": "^1.1.0",
|
16
21
|
"pinia": "^2.0.23",
|
17
22
|
"qs": "^6.11.0",
|
18
|
-
"
|
23
|
+
"unocss": "^0.48.2",
|
24
|
+
"vant": "^4.0.8",
|
19
25
|
"vue": "^3.2.41",
|
20
26
|
"vue-router": "^4.1.6"
|
21
27
|
},
|
22
28
|
"devDependencies": {
|
29
|
+
"@types/lodash-es": "^4.17.4",
|
23
30
|
"@types/node": "^17.0.42",
|
24
31
|
"@typescript-eslint/eslint-plugin": "^5.20.0",
|
25
32
|
"@typescript-eslint/parser": "^5.20.0",
|
@@ -47,9 +54,9 @@
|
|
47
54
|
"typescript": "^4.6.4",
|
48
55
|
"unplugin-auto-import": "^0.11.4",
|
49
56
|
"unplugin-vue-components": "^0.22.9",
|
50
|
-
"vite": "^4.0.
|
51
|
-
"vite-plugin-mock": "^2.9.6",
|
57
|
+
"vite": "^4.0.0",
|
52
58
|
"vite-plugin-html": "^3.2.0",
|
59
|
+
"vite-plugin-mock": "^2.9.6",
|
53
60
|
"vite-plugin-vue-setup-extend": "^0.4.0",
|
54
61
|
"vue-eslint-parser": "^9.1.0",
|
55
62
|
"vue-tsc": "^1.0.9"
|
@@ -1,7 +1,6 @@
|
|
1
1
|
import type { Ref } from 'vue'
|
2
2
|
import { ref, watch } from 'vue'
|
3
|
-
import {
|
4
|
-
import { ToastWrapperInstance } from 'vant/lib/toast/types'
|
3
|
+
import { closeToast, showLoadingToast } from 'vant'
|
5
4
|
import type { PageLoadingTpe } from '@/components/PageContainer'
|
6
5
|
|
7
6
|
export type SetLoadingParams<T> = { value: T; type?: PageLoadingTpe; message?: string }
|
@@ -11,7 +10,7 @@ type ChangeLoadingFn<T> = ({ value, type, message }: SetLoadingParams<T>) => voi
|
|
11
10
|
export default function usePageLoading<T, R = Ref<T>>({
|
12
11
|
defaultType,
|
13
12
|
defaultMessage,
|
14
|
-
defaultLoading
|
13
|
+
defaultLoading
|
15
14
|
}: {
|
16
15
|
defaultType?: PageLoadingTpe;
|
17
16
|
defaultMessage?: string;
|
@@ -27,21 +26,19 @@ export default function usePageLoading<T, R = Ref<T>>({
|
|
27
26
|
|
28
27
|
const loadingType = ref(defaultType)
|
29
28
|
|
30
|
-
const pageLoadingRef = ref<ToastWrapperInstance>()
|
31
|
-
|
32
29
|
watch(() => pageLoading.value, (val) => {
|
33
30
|
if (val) {
|
34
31
|
if (loadingType.value === 'toast') {
|
35
|
-
|
32
|
+
showLoadingToast({
|
36
33
|
duration: 0,
|
37
34
|
forbidClick: true,
|
38
35
|
message: loadingMessage.value || '加载中'
|
39
36
|
})
|
40
37
|
} else {
|
41
|
-
|
38
|
+
closeToast()
|
42
39
|
}
|
43
40
|
} else {
|
44
|
-
|
41
|
+
closeToast()
|
45
42
|
}
|
46
43
|
}, {
|
47
44
|
deep: true,
|
@@ -5,10 +5,6 @@
|
|
5
5
|
:loadingMsg="loadingMsg"
|
6
6
|
:hiddenSlot="hiddenSlot"
|
7
7
|
>
|
8
|
-
<van-swipe class="my-swipe">
|
9
|
-
<van-swipe-item>1</van-swipe-item>
|
10
|
-
<van-swipe-item>2</van-swipe-item>
|
11
|
-
</van-swipe>
|
12
8
|
<div style="display: flex;flex-direction: column;gap: 20px;">
|
13
9
|
<p>以下刷新只针对toast</p>
|
14
10
|
<van-button @click="init(true)">刷新(隐藏子组件)</van-button>
|
@@ -22,7 +18,7 @@
|
|
22
18
|
</template>
|
23
19
|
|
24
20
|
<script setup lang="ts">
|
25
|
-
import { isBoolean } from '
|
21
|
+
import { isBoolean } from '@gx-design-vue/pro-utils'
|
26
22
|
|
27
23
|
const loading = ref(false)
|
28
24
|
const pageContainer = ref()
|
@@ -72,11 +68,4 @@ const toggleLoading = (hiddenSlot: boolean, message?: string) => {
|
|
72
68
|
</script>
|
73
69
|
|
74
70
|
<style lang="less" scoped>
|
75
|
-
.my-swipe .van-swipe-item {
|
76
|
-
color: #fff;
|
77
|
-
font-size: 20px;
|
78
|
-
line-height: 150px;
|
79
|
-
text-align: center;
|
80
|
-
background-color: #39a9ed;
|
81
|
-
}
|
82
71
|
</style>
|
@@ -1,19 +1,18 @@
|
|
1
1
|
import type { App } from 'vue'
|
2
2
|
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
|
3
|
-
import
|
3
|
+
import settings from '@/settings'
|
4
4
|
import getPageTitle from '@/utils/pageTitle'
|
5
5
|
import { constantRoutes } from './routes'
|
6
6
|
|
7
|
-
const router = createRouter({
|
7
|
+
export const router = createRouter({
|
8
8
|
history: createWebHashHistory(),
|
9
9
|
routes: constantRoutes as unknown as RouteRecordRaw[]
|
10
10
|
})
|
11
11
|
|
12
12
|
const doRouterPermission = () => {
|
13
13
|
router.afterEach((to) => {
|
14
|
-
const global = useStoreGlobal()
|
15
14
|
const { meta }: any = to
|
16
|
-
document.title = getPageTitle(
|
15
|
+
document.title = getPageTitle(settings.title, meta.title || '')
|
17
16
|
})
|
18
17
|
}
|
19
18
|
|
@@ -9,8 +9,6 @@ import { deepCopy } from '@/utils/util'
|
|
9
9
|
* @description store-global 全局属性
|
10
10
|
*/
|
11
11
|
export interface GlobalState {
|
12
|
-
title: string; // app 应用名
|
13
|
-
tokenName?: string; // 请求header token key值
|
14
12
|
token?: string; // app token
|
15
13
|
}
|
16
14
|
|
@@ -18,8 +16,7 @@ type GlobalStateKey = keyof GlobalState
|
|
18
16
|
|
19
17
|
export const useStoreGlobal = defineStore('global', () => {
|
20
18
|
const state = reactive<GlobalState>({
|
21
|
-
|
22
|
-
tokenName: 'token'
|
19
|
+
token: ''
|
23
20
|
})
|
24
21
|
|
25
22
|
const setGlobalData: (params: Partial<Record<GlobalStateKey, GlobalState[GlobalStateKey]>>) => void = (params) => {
|
@@ -1,25 +1,39 @@
|
|
1
|
-
import
|
1
|
+
import 'crypto-js/enc-utf8'
|
2
|
+
import 'crypto-js/tripledes'
|
3
|
+
import 'crypto-js/sha1'
|
4
|
+
import * as CryptoJS from 'crypto-js/core'
|
5
|
+
import { isJSONStr } from '@/utils/validate'
|
6
|
+
import { isObject, isArray } from '@gx-design-vue/pro-utils'
|
2
7
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
let
|
8
|
-
|
8
|
+
const key = '1234123412ABCDEF' //十六位十六进制数作为密钥
|
9
|
+
|
10
|
+
//加密方法
|
11
|
+
export function Encrypt(word) {
|
12
|
+
let str: string | object = word
|
13
|
+
if (isObject(word) || isArray(word)) {
|
14
|
+
str = JSON.stringify(word)
|
15
|
+
}
|
16
|
+
const keyHex = CryptoJS.enc.Utf8.parse(key)
|
17
|
+
const ivHex = CryptoJS.enc.Utf8.parse(key)
|
18
|
+
const encrypted = CryptoJS.DES.encrypt(str, keyHex, {
|
19
|
+
iv: ivHex,
|
20
|
+
mode: CryptoJS.mode.CBC,
|
9
21
|
padding: CryptoJS.pad.Pkcs7
|
10
22
|
})
|
11
|
-
return
|
23
|
+
return CryptoJS.enc.Base64.stringify(encrypted.ciphertext)
|
12
24
|
}
|
13
25
|
|
14
|
-
|
15
|
-
export function
|
16
|
-
|
17
|
-
const
|
18
|
-
const
|
19
|
-
|
20
|
-
|
21
|
-
|
26
|
+
//解密方法
|
27
|
+
export function Decrypt(word) {
|
28
|
+
const keyHex = CryptoJS.enc.Utf8.parse(key)
|
29
|
+
const ivHex = CryptoJS.enc.Utf8.parse(key)
|
30
|
+
const decrypted = CryptoJS.DES.decrypt({
|
31
|
+
ciphertext: CryptoJS.enc.Base64.parse(word)
|
32
|
+
}, keyHex, {
|
33
|
+
iv: ivHex,
|
34
|
+
mode: CryptoJS.mode.CBC,
|
22
35
|
padding: CryptoJS.pad.Pkcs7
|
23
36
|
})
|
24
|
-
|
37
|
+
const decryptedStr = decrypted.toString(CryptoJS.enc.Utf8)
|
38
|
+
return isJSONStr(decryptedStr.toString()) ? JSON.parse(decryptedStr.toString()) : decryptedStr.toString()
|
25
39
|
}
|
@@ -43,7 +43,7 @@ export function isBuild(): boolean {
|
|
43
43
|
export function typeViteEnv(key: ViteEnvKey) {
|
44
44
|
let value = import.meta.env[key]
|
45
45
|
if (value) {
|
46
|
-
value = value.replace(/\\n/g, '\n')
|
46
|
+
value = (value as string).replace(/\\n/g, '\n')
|
47
47
|
|
48
48
|
value = value === 'true' ? true : value === 'false' ? false : value
|
49
49
|
}
|
@@ -0,0 +1,131 @@
|
|
1
|
+
import type { AxiosResponse, AxiosError } from 'axios'
|
2
|
+
import axios from 'axios'
|
3
|
+
import { deepCopy } from '@/utils/util'
|
4
|
+
import qs from 'qs'
|
5
|
+
import { isFunction } from '@gx-design-vue/pro-utils'
|
6
|
+
import type { GAxiosInstance, GAxiosOptions } from './typings'
|
7
|
+
import { ContentTypeEnum, RequestEnum } from './typings'
|
8
|
+
import { AxiosCanceler } from './axiosCancel'
|
9
|
+
|
10
|
+
/**
|
11
|
+
* @Author gx12358
|
12
|
+
* @DateTime 2023/1/6
|
13
|
+
* @lastTime 2023/1/6
|
14
|
+
* @description 重新定义axios
|
15
|
+
*/
|
16
|
+
export class GAxios {
|
17
|
+
private axiosInstance: GAxiosInstance
|
18
|
+
private readonly options: GAxiosOptions
|
19
|
+
|
20
|
+
constructor(options: GAxiosOptions) {
|
21
|
+
this.options = options
|
22
|
+
this.axiosInstance = axios.create(options)
|
23
|
+
this.setupInterceptors()
|
24
|
+
}
|
25
|
+
|
26
|
+
/**
|
27
|
+
* @description: Interceptor configuration 拦截器配置
|
28
|
+
*/
|
29
|
+
private setupInterceptors() {
|
30
|
+
const {
|
31
|
+
requestInterceptors,
|
32
|
+
requestInterceptorsCatch,
|
33
|
+
responseInterceptors,
|
34
|
+
responseInterceptorsCatch
|
35
|
+
} = this.options
|
36
|
+
|
37
|
+
const axiosCanceler = new AxiosCanceler()
|
38
|
+
|
39
|
+
this.axiosInstance.interceptors.request.use((config: GAxiosOptions) => {
|
40
|
+
const { ignoreCancelToken } = config
|
41
|
+
const ignoreCancel =
|
42
|
+
ignoreCancelToken !== undefined
|
43
|
+
? ignoreCancelToken
|
44
|
+
: this.options?.ignoreCancelToken
|
45
|
+
|
46
|
+
!ignoreCancel && axiosCanceler.addPending(config)
|
47
|
+
if (requestInterceptors && isFunction(requestInterceptors)) {
|
48
|
+
config = requestInterceptors(config)
|
49
|
+
}
|
50
|
+
return config
|
51
|
+
}, undefined)
|
52
|
+
|
53
|
+
// Request interceptor error capture
|
54
|
+
requestInterceptorsCatch &&
|
55
|
+
isFunction(requestInterceptorsCatch) &&
|
56
|
+
this.axiosInstance.interceptors.request.use(undefined, requestInterceptorsCatch)
|
57
|
+
|
58
|
+
// Response result interceptor processing
|
59
|
+
this.axiosInstance.interceptors.response.use((res: AxiosResponse) => {
|
60
|
+
res && axiosCanceler.removePending(res.config)
|
61
|
+
if (responseInterceptors && isFunction(responseInterceptors)) {
|
62
|
+
return responseInterceptors(res)
|
63
|
+
}
|
64
|
+
return res
|
65
|
+
}, undefined)
|
66
|
+
|
67
|
+
// Response result interceptor error capture
|
68
|
+
responseInterceptorsCatch &&
|
69
|
+
isFunction(responseInterceptorsCatch) &&
|
70
|
+
this.axiosInstance.interceptors.response.use(undefined, (error) => {
|
71
|
+
return responseInterceptorsCatch(this.axiosInstance, error)
|
72
|
+
})
|
73
|
+
}
|
74
|
+
|
75
|
+
// support form-data
|
76
|
+
supportFormData(config: GAxiosOptions) {
|
77
|
+
const headers = config.headers || this.options.headers
|
78
|
+
const contentType = headers?.['Content-Type'] || headers?.['content-type']
|
79
|
+
|
80
|
+
if (
|
81
|
+
contentType !== ContentTypeEnum.FORM_URLENCODED ||
|
82
|
+
!Reflect.has(config, 'data') ||
|
83
|
+
config.method?.toUpperCase() === RequestEnum.GET
|
84
|
+
) {
|
85
|
+
return config
|
86
|
+
}
|
87
|
+
|
88
|
+
return {
|
89
|
+
...config,
|
90
|
+
data: qs.stringify(config.data, { arrayFormat: 'brackets' })
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
request<T = ResponseResult | boolean>(config: GAxiosOptions): Promise<T> {
|
95
|
+
let conf: GAxiosOptions = deepCopy(config)
|
96
|
+
|
97
|
+
const opt: GAxiosOptions = Object.assign({}, this.options, conf)
|
98
|
+
|
99
|
+
const { beforeRequestHook, requestCatchHook, transformResponseHook } = opt
|
100
|
+
if (beforeRequestHook && isFunction(beforeRequestHook)) {
|
101
|
+
conf = beforeRequestHook(opt)
|
102
|
+
}
|
103
|
+
|
104
|
+
conf = this.supportFormData(opt)
|
105
|
+
|
106
|
+
return new Promise((resolve) => {
|
107
|
+
this.axiosInstance
|
108
|
+
.request<any, AxiosResponse>(conf)
|
109
|
+
.then((res: AxiosResponse) => {
|
110
|
+
if (transformResponseHook && isFunction(transformResponseHook)) {
|
111
|
+
try {
|
112
|
+
const ret = transformResponseHook(res, config)
|
113
|
+
resolve(ret)
|
114
|
+
} catch (err) {
|
115
|
+
resolve(false as any)
|
116
|
+
return
|
117
|
+
}
|
118
|
+
return
|
119
|
+
}
|
120
|
+
resolve(res as unknown as Promise<T>)
|
121
|
+
})
|
122
|
+
.catch((e: Error | AxiosError) => {
|
123
|
+
if (requestCatchHook && isFunction(requestCatchHook)) {
|
124
|
+
resolve(requestCatchHook(e) as any)
|
125
|
+
return
|
126
|
+
}
|
127
|
+
resolve(false as any)
|
128
|
+
})
|
129
|
+
})
|
130
|
+
}
|
131
|
+
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import type { AxiosRequestConfig, Canceler } from 'axios'
|
2
|
+
import axios from 'axios'
|
3
|
+
import { isFunction } from '@gx-design-vue/pro-utils'
|
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
|
+
}
|