feat: 增加代码
This commit is contained in:
commit
9284f8029b
1
.eslintignore
Normal file
1
.eslintignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
git-static.js
|
3
.eslintrc.js
Normal file
3
.eslintrc.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: ['@mistjs'],
|
||||||
|
}
|
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.log
|
||||||
|
node_modules
|
||||||
|
.DS_Store
|
||||||
|
dist
|
||||||
|
|
||||||
|
git-static.js
|
4
.husky/commit-msg
Normal file
4
.husky/commit-msg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
. "$(dirname -- "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
npx --no-install commitlint --edit $1
|
4
.husky/pre-commit
Normal file
4
.husky/pre-commit
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
. "$(dirname -- "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
npx --no-install lint-staged
|
2
.npmrc
Normal file
2
.npmrc
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
registry=http://10.0.59.229:5055/
|
||||||
|
//10.0.59.229:5055/:_authToken="zkijreGTZRgAkrch3Qza8pwSpWNeg0tWTBHhnM32rsY="
|
15
README.md
Normal file
15
README.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# @crami/http@2.x
|
||||||
|
|
||||||
|
## 开发
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# 安装依赖
|
||||||
|
pnpm i
|
||||||
|
|
||||||
|
# 版本发布
|
||||||
|
pnpm release
|
||||||
|
```
|
||||||
|
|
||||||
|
### 版本发布注意事项
|
||||||
|
|
||||||
|
本项目使用自动化版本发布脚本,执行release以后,选择对应的版本号,会自动tag一个版本号。查看版本自动发布流程前往[droneCI](http://10.0.59.229:8119/),找到对应的项目即可查看。
|
12
build.config.ts
Normal file
12
build.config.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { defineBuildConfig } from 'unbuild'
|
||||||
|
|
||||||
|
export default defineBuildConfig({
|
||||||
|
entries: [
|
||||||
|
'src/index',
|
||||||
|
],
|
||||||
|
rollup: {
|
||||||
|
emitCJS: true,
|
||||||
|
},
|
||||||
|
externals: ['axios', 'vue'],
|
||||||
|
declaration: true,
|
||||||
|
})
|
6
commitlint.config.js
Normal file
6
commitlint.config.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: ['@commitlint/config-conventional'],
|
||||||
|
rules: {
|
||||||
|
'type-enum': [2, 'always', ['feat', 'fix', 'style', 'refactor', 'perf', 'test', 'build', 'chore', 'revert', 'release']],
|
||||||
|
},
|
||||||
|
}
|
58
package.json
Normal file
58
package.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"name": "@crami/http",
|
||||||
|
"version": "2.0.10",
|
||||||
|
"packageManager": "pnpm@7.1.7",
|
||||||
|
"description": "this is crami http",
|
||||||
|
"keywords": [],
|
||||||
|
"license": "ISC",
|
||||||
|
"author": "crami-original",
|
||||||
|
"main": "dist/index.cjs",
|
||||||
|
"module": "dist/index.mjs",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"playground": "vite dev playground --port 7788 --open",
|
||||||
|
"prepare": "husky install",
|
||||||
|
"preinstall": "npx only-allow pnpm",
|
||||||
|
"build": "unbuild",
|
||||||
|
"stub": "unbuild --stub",
|
||||||
|
"release": "bumpp package.json --commit \"release: v\" --push --tag",
|
||||||
|
"prepublish": "pnpm build",
|
||||||
|
"pb": "pnpm publish --registry=http://10.0.59.229:5055/ --no-git-checks",
|
||||||
|
"pb:b": "pnpm publish --registry=http://10.0.59.229:5055/ --no-git-checks --tag=beta"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.27.2",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"qs": "^6.10.5",
|
||||||
|
"vue": "^3.2.36"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@commitlint/cli": "^17.0.2",
|
||||||
|
"@unocss/reset": "^0.37.4",
|
||||||
|
"@commitlint/config-conventional": "^17.0.2",
|
||||||
|
"@iconify-json/carbon": "^1.1.5",
|
||||||
|
"@mistjs/eslint-config": "^0.0.2",
|
||||||
|
"@types/lodash": "^4.14.182",
|
||||||
|
"@types/node": "^17.0.40",
|
||||||
|
"@types/qs": "^6.9.7",
|
||||||
|
"@vitejs/plugin-vue": "^2.3.3",
|
||||||
|
"@vue/tsconfig": "^0.1.3",
|
||||||
|
"bumpp": "^7.1.1",
|
||||||
|
"eslint": "^8.17.0",
|
||||||
|
"husky": "^8.0.1",
|
||||||
|
"lint-staged": "^13.0.0",
|
||||||
|
"npm-run-all": "^4.1.5",
|
||||||
|
"typescript": "^4.7.3",
|
||||||
|
"unbuild": "^0.7.4",
|
||||||
|
"unocss": "^0.37.4",
|
||||||
|
"vite": "^2.9.9",
|
||||||
|
"vitest": "^0.14.0",
|
||||||
|
"vue-tsc": "^0.35.2"
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"*.{ts,tsx,js,vue}": "eslint src --fix"
|
||||||
|
}
|
||||||
|
}
|
28
playground/.gitignore
vendored
Normal file
28
playground/.gitignore
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
.DS_Store
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
coverage
|
||||||
|
*.local
|
||||||
|
|
||||||
|
/cypress/videos/
|
||||||
|
/cypress/screenshots/
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
40
playground/README.md
Normal file
40
playground/README.md
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# playground
|
||||||
|
|
||||||
|
This template should help get you started developing with Vue 3 in Vite.
|
||||||
|
|
||||||
|
## Recommended IDE Setup
|
||||||
|
|
||||||
|
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
|
||||||
|
|
||||||
|
## Type Support for `.vue` Imports in TS
|
||||||
|
|
||||||
|
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
|
||||||
|
|
||||||
|
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
|
||||||
|
|
||||||
|
1. Disable the built-in TypeScript Extension
|
||||||
|
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
|
||||||
|
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
|
||||||
|
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
|
||||||
|
|
||||||
|
## Customize configuration
|
||||||
|
|
||||||
|
See [Vite Configuration Reference](https://vitejs.dev/config/).
|
||||||
|
|
||||||
|
## Project Setup
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pnpm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compile and Hot-Reload for Development
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pnpm dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Type-Check, Compile and Minify for Production
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pnpm build
|
||||||
|
```
|
1
playground/env.d.ts
vendored
Normal file
1
playground/env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/// <reference types="vite/client" />
|
17
playground/index.html
Normal file
17
playground/index.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Crami Http</title>
|
||||||
|
<style>
|
||||||
|
html{
|
||||||
|
background: #121212;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
13
playground/src/App.vue
Normal file
13
playground/src/App.vue
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import GetComp from './components/get.vue'
|
||||||
|
import PostComp from './components/post.vue'
|
||||||
|
import Upload from './components/upload.vue'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<get-comp />
|
||||||
|
<post-comp />
|
||||||
|
<Upload />
|
||||||
|
</div>
|
||||||
|
</template>
|
10
playground/src/api/index.ts
Normal file
10
playground/src/api/index.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export interface RequestParams{
|
||||||
|
username?: string
|
||||||
|
password?: string
|
||||||
|
}
|
||||||
|
export interface ResponseData{
|
||||||
|
data?: any
|
||||||
|
success?: boolean
|
||||||
|
code: number
|
||||||
|
msg: string
|
||||||
|
}
|
74
playground/src/assets/base.css
Normal file
74
playground/src/assets/base.css
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/* color palette from <https://github.com/vuejs/theme> */
|
||||||
|
:root {
|
||||||
|
--vt-c-white: #ffffff;
|
||||||
|
--vt-c-white-soft: #f8f8f8;
|
||||||
|
--vt-c-white-mute: #f2f2f2;
|
||||||
|
|
||||||
|
--vt-c-black: #181818;
|
||||||
|
--vt-c-black-soft: #222222;
|
||||||
|
--vt-c-black-mute: #282828;
|
||||||
|
|
||||||
|
--vt-c-indigo: #2c3e50;
|
||||||
|
|
||||||
|
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
|
||||||
|
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
|
||||||
|
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
|
||||||
|
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
|
||||||
|
|
||||||
|
--vt-c-text-light-1: var(--vt-c-indigo);
|
||||||
|
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
|
||||||
|
--vt-c-text-dark-1: var(--vt-c-white);
|
||||||
|
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* semantic color variables for this project */
|
||||||
|
:root {
|
||||||
|
--color-background: var(--vt-c-white);
|
||||||
|
--color-background-soft: var(--vt-c-white-soft);
|
||||||
|
--color-background-mute: var(--vt-c-white-mute);
|
||||||
|
|
||||||
|
--color-border: var(--vt-c-divider-light-2);
|
||||||
|
--color-border-hover: var(--vt-c-divider-light-1);
|
||||||
|
|
||||||
|
--color-heading: var(--vt-c-text-light-1);
|
||||||
|
--color-text: var(--vt-c-text-light-1);
|
||||||
|
|
||||||
|
--section-gap: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--color-background: var(--vt-c-black);
|
||||||
|
--color-background-soft: var(--vt-c-black-soft);
|
||||||
|
--color-background-mute: var(--vt-c-black-mute);
|
||||||
|
|
||||||
|
--color-border: var(--vt-c-divider-dark-2);
|
||||||
|
--color-border-hover: var(--vt-c-divider-dark-1);
|
||||||
|
|
||||||
|
--color-heading: var(--vt-c-text-dark-1);
|
||||||
|
--color-text: var(--vt-c-text-dark-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
position: relative;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
min-height: 100vh;
|
||||||
|
color: var(--color-text);
|
||||||
|
background: var(--color-background);
|
||||||
|
transition: color 0.5s, background-color 0.5s;
|
||||||
|
line-height: 1.6;
|
||||||
|
font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
|
||||||
|
Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
||||||
|
font-size: 15px;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
1
playground/src/assets/logo.svg
Normal file
1
playground/src/assets/logo.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69" xmlns:v="https://vecta.io/nano"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
|
After Width: | Height: | Size: 308 B |
49
playground/src/components/get.vue
Normal file
49
playground/src/components/get.vue
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { Http, useGet, useHttp } from '@crami/http'
|
||||||
|
import type { ResponseData } from '~/api'
|
||||||
|
|
||||||
|
const handleGet = async() => {
|
||||||
|
const data = await Http.get<ResponseData>({
|
||||||
|
url: '/api/table/columns',
|
||||||
|
})
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUseHttp = async() => {
|
||||||
|
const data = await useHttp<ResponseData>({
|
||||||
|
url: '/api/table/columns',
|
||||||
|
params: {
|
||||||
|
aaa: 'SAdasdas',
|
||||||
|
nnn: 'dasdasd',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
const useGetData = async() => {
|
||||||
|
const data = await useGet('/api/table/columns')
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div p-3>
|
||||||
|
<div text-white mb-2>
|
||||||
|
Get类型请求测试
|
||||||
|
</div>
|
||||||
|
<div flex="~ wrap gap-2">
|
||||||
|
<button btn @click="handleGet">
|
||||||
|
Http测试请求
|
||||||
|
</button>
|
||||||
|
<button btn @click="handleUseHttp">
|
||||||
|
useHttp请求测试
|
||||||
|
</button>
|
||||||
|
<button btn @click="useGetData">
|
||||||
|
useGet请求测试
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
54
playground/src/components/post.vue
Normal file
54
playground/src/components/post.vue
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { Http, useHttp, usePost } from '@crami/http'
|
||||||
|
import type { RequestParams, ResponseData } from '~/api'
|
||||||
|
|
||||||
|
const handleGet = async() => {
|
||||||
|
const data = await Http.post<ResponseData>({
|
||||||
|
url: '/api/date/table/data',
|
||||||
|
})
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUseHttp = async() => {
|
||||||
|
const data = await useHttp<ResponseData>({
|
||||||
|
url: '/api/date/table/data',
|
||||||
|
method: 'POST',
|
||||||
|
data: [
|
||||||
|
'1', '2',
|
||||||
|
],
|
||||||
|
})
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
const useGetData = async() => {
|
||||||
|
const data = await usePost<ResponseData, RequestParams>(
|
||||||
|
'/api/date/table/data',
|
||||||
|
{
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
})
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div p-3>
|
||||||
|
<div text-white mb-2>
|
||||||
|
Post类型请求测试
|
||||||
|
</div>
|
||||||
|
<div flex="~ wrap gap-2">
|
||||||
|
<button btn @click="handleGet">
|
||||||
|
Http测试请求
|
||||||
|
</button>
|
||||||
|
<button btn @click="handleUseHttp">
|
||||||
|
useHttp请求测试
|
||||||
|
</button>
|
||||||
|
<button btn @click="useGetData">
|
||||||
|
usePost请求测试
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
31
playground/src/components/upload.vue
Normal file
31
playground/src/components/upload.vue
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { Http } from '@crami/http'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
const file = ref<File>()
|
||||||
|
const handleChange = (e: any) => {
|
||||||
|
// console.log(e.target.files)
|
||||||
|
file.value = e.target.files[0]
|
||||||
|
}
|
||||||
|
const handleGet = () => {
|
||||||
|
Http.uploadFile({
|
||||||
|
url: '/api/table/columns',
|
||||||
|
}, {
|
||||||
|
filename: 'test.txt',
|
||||||
|
file: file.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div p-3>
|
||||||
|
<div text-white mb-2>
|
||||||
|
文件上传测试
|
||||||
|
</div>
|
||||||
|
<div flex="~ wrap gap-2">
|
||||||
|
<input type="file" @change="handleChange">
|
||||||
|
<button btn @click="handleGet">
|
||||||
|
文件上传测试
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
34
playground/src/main.ts
Normal file
34
playground/src/main.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { createApp } from 'vue'
|
||||||
|
import { createAxios, createHttp, icpxTransform, icpxTransformConfig } from '@crami/http'
|
||||||
|
import App from './App.vue'
|
||||||
|
import '@unocss/reset/tailwind.css'
|
||||||
|
import 'uno.css'
|
||||||
|
|
||||||
|
const axios = createAxios({
|
||||||
|
baseURL: '/',
|
||||||
|
})
|
||||||
|
|
||||||
|
axios.interceptors.request.use((config) => {
|
||||||
|
return config
|
||||||
|
})
|
||||||
|
|
||||||
|
axios.interceptors.response.use((response) => {
|
||||||
|
return response.data
|
||||||
|
})
|
||||||
|
|
||||||
|
// axios.interceptors.request = function() {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
const http = createHttp(axios, {
|
||||||
|
responseTransform: icpxTransform,
|
||||||
|
requestTransform: icpxTransformConfig,
|
||||||
|
headers: () => ({
|
||||||
|
token: 'this is my token',
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const app = createApp(App)
|
||||||
|
|
||||||
|
app.use(http)
|
||||||
|
|
||||||
|
app.mount('#app')
|
38
playground/unocss.config.ts
Normal file
38
playground/unocss.config.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import {
|
||||||
|
defineConfig,
|
||||||
|
presetAttributify,
|
||||||
|
presetIcons,
|
||||||
|
presetTypography,
|
||||||
|
presetUno,
|
||||||
|
presetWebFonts,
|
||||||
|
transformerDirectives,
|
||||||
|
transformerVariantGroup,
|
||||||
|
} from 'unocss'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
shortcuts: [
|
||||||
|
['btn', 'px-4 py-1 rounded inline-block bg-teal-700 text-white cursor-pointer hover:bg-teal-800 disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50'],
|
||||||
|
['icon-btn', 'inline-block cursor-pointer select-none opacity-75 transition duration-200 ease-in-out hover:opacity-100 hover:text-teal-600'],
|
||||||
|
],
|
||||||
|
presets: [
|
||||||
|
presetUno(),
|
||||||
|
presetAttributify(),
|
||||||
|
presetIcons({
|
||||||
|
scale: 1.2,
|
||||||
|
warn: true,
|
||||||
|
}),
|
||||||
|
presetTypography(),
|
||||||
|
presetWebFonts({
|
||||||
|
fonts: {
|
||||||
|
sans: 'DM Sans',
|
||||||
|
serif: 'DM Serif Display',
|
||||||
|
mono: 'DM Mono',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
transformers: [
|
||||||
|
transformerDirectives(),
|
||||||
|
transformerVariantGroup(),
|
||||||
|
],
|
||||||
|
safelist: 'prose prose-sm m-auto text-left'.split(' '),
|
||||||
|
})
|
30
playground/vite.config.ts
Normal file
30
playground/vite.config.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { URL, fileURLToPath } from 'url'
|
||||||
|
import Unocss from 'unocss/vite'
|
||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
vue({
|
||||||
|
reactivityTransform: true,
|
||||||
|
}),
|
||||||
|
Unocss(),
|
||||||
|
],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@crami/http': fileURLToPath(new URL('../src', import.meta.url)),
|
||||||
|
'~/': fileURLToPath(new URL('./src/', import.meta.url)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'http://10.0.59.229:7300/mock/622ff143ec91f63c580c0560',
|
||||||
|
rewrite: (path) => {
|
||||||
|
return path.replace(/^\/api/, '')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
5212
pnpm-lock.yaml
Normal file
5212
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load Diff
64
src/composables/http.ts
Normal file
64
src/composables/http.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import type { BaseApi } from '../typing'
|
||||||
|
import { Http } from '../constant'
|
||||||
|
|
||||||
|
type RequestBaseApiType = Omit<BaseApi, 'url'|'params'|'method'|'data'>
|
||||||
|
function useHttp <R=any, D=any>(api: BaseApi<D>): Promise<R> {
|
||||||
|
return Http.request<R, D>(api)
|
||||||
|
}
|
||||||
|
|
||||||
|
function useRequest<R, D = any>(url: string, options?: Omit<BaseApi<D>, 'url'>): Promise<R> {
|
||||||
|
return useHttp<R, D>({
|
||||||
|
...(options || {}),
|
||||||
|
url,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function useGet<R, D = any>(url: string, params?: D, options?: RequestBaseApiType): Promise<R> {
|
||||||
|
return Http.get<R, D>({
|
||||||
|
...(options || {}),
|
||||||
|
url,
|
||||||
|
params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function usePost<R, D = any>(url: string, data?: D, options?: RequestBaseApiType): Promise<R> {
|
||||||
|
return Http.post<R, D>({
|
||||||
|
...(options || {}),
|
||||||
|
url,
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function usePut<R, D = any>(url: string, data?: D, options?: RequestBaseApiType): Promise<R> {
|
||||||
|
return Http.put<R, D>({
|
||||||
|
...(options || {}),
|
||||||
|
url,
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function useDelete<R, D=any>(url: string, data?: D, options?: RequestBaseApiType): Promise<R> {
|
||||||
|
return Http.delete<R, D>({
|
||||||
|
...(options || {}),
|
||||||
|
url,
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function useUpload<R>(url: string, data?: FormData, options?: RequestBaseApiType): Promise<R> {
|
||||||
|
return Http.upload<R>({
|
||||||
|
...(options || {}),
|
||||||
|
url,
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
useRequest,
|
||||||
|
useGet,
|
||||||
|
usePost,
|
||||||
|
usePut,
|
||||||
|
useDelete,
|
||||||
|
useUpload,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useHttp
|
62
src/constant.ts
Normal file
62
src/constant.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import type { InitHttpCallback } from './init-http'
|
||||||
|
import type { CramiHttpOptions } from './typing'
|
||||||
|
|
||||||
|
export interface HttpObjType extends Partial<InitHttpCallback>{
|
||||||
|
__isMerging?: boolean
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
// 去除vue中的白名单
|
||||||
|
const ALLOW_WHITE_LIST = [
|
||||||
|
'__isVue',
|
||||||
|
'__v_isRef',
|
||||||
|
'__v_isReadonly',
|
||||||
|
'__v_isReactive',
|
||||||
|
]
|
||||||
|
|
||||||
|
const ERROR_LIST = [
|
||||||
|
'request',
|
||||||
|
'get',
|
||||||
|
'post',
|
||||||
|
'put',
|
||||||
|
'delete',
|
||||||
|
'option',
|
||||||
|
]
|
||||||
|
|
||||||
|
const httpObj: HttpObjType = {
|
||||||
|
__isMerging: false,
|
||||||
|
}
|
||||||
|
export const Http: InitHttpCallback = new Proxy(
|
||||||
|
httpObj, {
|
||||||
|
get: (target, key) => {
|
||||||
|
const isExist = Reflect.has(target, key)
|
||||||
|
// 如果我们想要的属性不存在,就给他报错
|
||||||
|
if (!isExist && !target.__isMerging && !ALLOW_WHITE_LIST.includes(String(key))) {
|
||||||
|
if (ERROR_LIST.includes(String(key)))
|
||||||
|
console.error(`Http.${String(key)} is not exist,maybe you forgot to import {createHttp} from "@crami/http" to init it`)
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return Reflect.get(target, key)
|
||||||
|
},
|
||||||
|
set(target, key, value) {
|
||||||
|
return Reflect.set(target, key, value)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
) as InitHttpCallback
|
||||||
|
|
||||||
|
interface AppOptions{
|
||||||
|
hooks: Omit<CramiHttpOptions, 'headers'>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const app: AppOptions = {
|
||||||
|
hooks: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ContentTypeEnum {
|
||||||
|
// json
|
||||||
|
JSON = 'application/json;charset=UTF-8',
|
||||||
|
// form-data qs
|
||||||
|
FORM = 'application/x-www-form-urlencoded;charset=UTF-8',
|
||||||
|
// form-data upload
|
||||||
|
UPLOAD = 'multipart/form-data;charset=UTF-8',
|
||||||
|
}
|
7
src/create-axios.ts
Normal file
7
src/create-axios.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
import type { AxiosInstance, AxiosRequestConfig } from 'axios'
|
||||||
|
|
||||||
|
export const createAxios = (config: AxiosRequestConfig): AxiosInstance => {
|
||||||
|
// TODO
|
||||||
|
return axios.create(config)
|
||||||
|
}
|
27
src/create-http.ts
Normal file
27
src/create-http.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import type { AxiosInstance } from 'axios'
|
||||||
|
import type { App, Plugin } from 'vue'
|
||||||
|
import { merge } from 'lodash'
|
||||||
|
import type { CramiHttpOptions } from './typing'
|
||||||
|
import initOptions from './init-options'
|
||||||
|
import type { InitHttpCallback } from './init-http'
|
||||||
|
import initHttp from './init-http'
|
||||||
|
import { Http } from './constant'
|
||||||
|
|
||||||
|
export const createHttp = (instance: AxiosInstance, options?: CramiHttpOptions): Plugin &{ version: string } => {
|
||||||
|
// 初始化配置
|
||||||
|
initOptions(instance, options)
|
||||||
|
// 创建axios实例
|
||||||
|
const InitHttp = initHttp(instance) as InitHttpCallback
|
||||||
|
// 合并实例
|
||||||
|
(Http as any).__isMerging = true
|
||||||
|
merge(Http as any, InitHttp);
|
||||||
|
(Http as any).__isMerging = false
|
||||||
|
delete (Http as any).__isMerging
|
||||||
|
// 返回需要实例化的对象的信息
|
||||||
|
return {
|
||||||
|
version: '2.0.0',
|
||||||
|
install: (app: App) => {
|
||||||
|
app.config.globalProperties.$http = Http
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
17
src/index.ts
Normal file
17
src/index.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { createAxios } from './create-axios'
|
||||||
|
import { createHttp } from './create-http'
|
||||||
|
import { ContentTypeEnum, Http } from './constant'
|
||||||
|
import useHttp from './composables/http'
|
||||||
|
export * from './composables/http'
|
||||||
|
export * from './transformer'
|
||||||
|
export type { BaseApi, CramiHttpOptions, HttpHeaderType } from './typing'
|
||||||
|
export type { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosResponseHeaders, AxiosResponseTransformer, AxiosRequestTransformer, AxiosRequestHeaders } from 'axios'
|
||||||
|
export {
|
||||||
|
createAxios,
|
||||||
|
createHttp,
|
||||||
|
Http,
|
||||||
|
useHttp,
|
||||||
|
ContentTypeEnum,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default createHttp
|
182
src/init-http.ts
Normal file
182
src/init-http.ts
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
import type { AxiosInstance, AxiosRequestConfig } from 'axios'
|
||||||
|
import qs from 'qs'
|
||||||
|
import { ContentTypeEnum, app } from './constant'
|
||||||
|
import { defaultTransform, defaultTransformConfig } from './transformer'
|
||||||
|
|
||||||
|
import type { BaseApi } from './typing'
|
||||||
|
import { checkContentType, checkIsGet, checkParams, isString, runFunction } from './utils'
|
||||||
|
type BaseApiNoMethod<D> = Omit<BaseApi<D>, 'method'>
|
||||||
|
|
||||||
|
interface UploadFileParams<D>{
|
||||||
|
data?: D
|
||||||
|
name?: string
|
||||||
|
file: File | Blob
|
||||||
|
filename?: string
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InitHttpCallback {
|
||||||
|
request <R=any, D=any>(config: BaseApi<D>): Promise<R>
|
||||||
|
get <R=any, D=any>(config: BaseApiNoMethod<D>): Promise<R>
|
||||||
|
post <R=any, D=any>(config: BaseApiNoMethod<D>): Promise<R>
|
||||||
|
put <R=any, D=any>(config: BaseApiNoMethod<D>): Promise<R>
|
||||||
|
form <R=any, D=any>(config: BaseApiNoMethod<D>): Promise<R>
|
||||||
|
upload <R=any>(config: BaseApiNoMethod<FormData>): Promise<R>
|
||||||
|
delete <R=any, D=any>(config: BaseApiNoMethod<D>): Promise<R>
|
||||||
|
uploadFile <R=any, D=any>(config: Omit<BaseApiNoMethod<any>, 'params'|'data'>, params: UploadFileParams<D>): Promise<R>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function initHttp(instance: AxiosInstance): InitHttpCallback {
|
||||||
|
// 请求request
|
||||||
|
async function request<R = any, D=any>(config: BaseApi<D>): Promise<R> {
|
||||||
|
const { beforeRequest, afterRequest, beforeRequestConfig, beforeRequestQuery, onError, responseTransform, urlParser, requestTransform, dataType, ...restConfig } = config
|
||||||
|
let newConfig
|
||||||
|
// 处理请求类型
|
||||||
|
if (dataType) {
|
||||||
|
switch (dataType) {
|
||||||
|
case 'form':
|
||||||
|
restConfig.headers = {
|
||||||
|
...restConfig.headers,
|
||||||
|
'Content-type': ContentTypeEnum.FORM,
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'upload':
|
||||||
|
restConfig.headers = {
|
||||||
|
...restConfig.headers,
|
||||||
|
'Content-type': ContentTypeEnum.UPLOAD,
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'json':
|
||||||
|
restConfig.headers = {
|
||||||
|
...restConfig.headers,
|
||||||
|
'Content-type': ContentTypeEnum.JSON,
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
if (!checkContentType(restConfig.headers as any)) {
|
||||||
|
restConfig.headers = {
|
||||||
|
...restConfig.headers,
|
||||||
|
'Content-type': ContentTypeEnum.JSON,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const requestFun = requestTransform || app.hooks?.requestTransform || defaultTransformConfig
|
||||||
|
newConfig = checkParams(requestFun(restConfig), restConfig)
|
||||||
|
newConfig = checkParams(await runFunction<AxiosRequestConfig<D>>(app.hooks?.beforeRequestConfig, newConfig), newConfig)
|
||||||
|
newConfig = checkParams(await runFunction<AxiosRequestConfig<D>>(beforeRequestConfig, newConfig), newConfig)
|
||||||
|
// 拦截url的处理钩子
|
||||||
|
newConfig.url = checkParams(await runFunction(app.hooks?.urlParser, newConfig.url), newConfig.url)
|
||||||
|
newConfig.url = checkParams(await runFunction(urlParser, newConfig.url), newConfig.url)
|
||||||
|
// GET 请求钩子特殊处理
|
||||||
|
if (checkIsGet(newConfig?.method)) {
|
||||||
|
// 全局的钩子
|
||||||
|
newConfig.params = checkParams(await runFunction(app.hooks?.beforeRequest, newConfig.params), newConfig.params)
|
||||||
|
// 单个请求的钩子
|
||||||
|
newConfig.params = checkParams(await runFunction(beforeRequest, newConfig.params), newConfig.params)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 管他存不存在的都要走这些钩子
|
||||||
|
newConfig.data = checkParams(await runFunction(app.hooks?.beforeRequest, newConfig.data), newConfig.data)
|
||||||
|
newConfig.data = checkParams(await runFunction(beforeRequest, newConfig.data), newConfig.data)
|
||||||
|
// 如果存在query的参数,就直接使用
|
||||||
|
newConfig.params = checkParams(await runFunction(app.hooks?.beforeRequestQuery, newConfig.params), newConfig.params)
|
||||||
|
newConfig.params = checkParams(await runFunction(beforeRequestQuery, newConfig.params), newConfig.params)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let response = await instance.request<R>(newConfig)
|
||||||
|
// 请求后的钩子函数
|
||||||
|
response = await checkParams(await runFunction(afterRequest, response), response)
|
||||||
|
// transform优先级从左到右,由大到小: 接口自定义 -> 全局自定义 -> 默认
|
||||||
|
const responseFun = responseTransform || app.hooks?.responseTransform || defaultTransform
|
||||||
|
// 这里还可以加处理
|
||||||
|
return responseFun(response)
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
app.hooks?.onError?.(e)
|
||||||
|
// TODO
|
||||||
|
onError?.(e)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get请求
|
||||||
|
async function get<R=any, D=any>(config: BaseApiNoMethod<D>): Promise<R> {
|
||||||
|
return request<R, D>({ ...config, method: 'GET' })
|
||||||
|
}
|
||||||
|
// POST请求
|
||||||
|
async function post<R=any, D=any>(config: BaseApiNoMethod<D>): Promise<R> {
|
||||||
|
return request<R, D>({ ...config, method: 'POST' })
|
||||||
|
}
|
||||||
|
// Put请求
|
||||||
|
async function put<R=any, D=any>(config: BaseApiNoMethod<D>): Promise<R> {
|
||||||
|
return request<R, D>({ ...config, method: 'PUT' })
|
||||||
|
}
|
||||||
|
// delete请求
|
||||||
|
async function deleteFun<R=any, D=any>(config: BaseApiNoMethod<D>): Promise<R> {
|
||||||
|
return request<R, D>({ ...config, method: 'DELETE' })
|
||||||
|
}
|
||||||
|
// upload请求
|
||||||
|
async function upload<R=any>(config: BaseApiNoMethod<FormData>): Promise<R> {
|
||||||
|
return request<R>({
|
||||||
|
...config,
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
...config.headers,
|
||||||
|
'Content-Type': ContentTypeEnum.UPLOAD,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function uploadFile<R=any, D = any>(config: Omit<BaseApiNoMethod<any>, 'params'|'data'>, params: UploadFileParams<D>): Promise<R> {
|
||||||
|
// 处理上传文件类型
|
||||||
|
const formData = new FormData()
|
||||||
|
if (params.data) {
|
||||||
|
for (const pKey in params.data) {
|
||||||
|
const value = params.data[pKey]
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
value.forEach((item) => {
|
||||||
|
formData.append(`${pKey}[]`, item)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
formData.append(pKey, (value as any))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
formData.append(params.name || 'file', params.file, params.filename)
|
||||||
|
if (params.filename)
|
||||||
|
formData.append('fileName', params.filename)
|
||||||
|
|
||||||
|
return upload<R>(
|
||||||
|
{
|
||||||
|
...config,
|
||||||
|
data: formData,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// form请求
|
||||||
|
async function form<R=any, D=any>(config: BaseApiNoMethod<D>): Promise<R> {
|
||||||
|
return request<R, string>({
|
||||||
|
...config,
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
...config.headers,
|
||||||
|
'Content-Type': ContentTypeEnum.FORM,
|
||||||
|
},
|
||||||
|
data: isString(config.data) ? config.data : qs.stringify(config.data),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
request,
|
||||||
|
get,
|
||||||
|
delete: deleteFun,
|
||||||
|
post,
|
||||||
|
upload,
|
||||||
|
form,
|
||||||
|
put,
|
||||||
|
uploadFile,
|
||||||
|
}
|
||||||
|
}
|
25
src/init-options.ts
Normal file
25
src/init-options.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import type { AxiosInstance } from 'axios'
|
||||||
|
import { merge, omit } from 'lodash'
|
||||||
|
import { ContentTypeEnum, app } from './constant'
|
||||||
|
import type { CramiHttpOptions, HttpHeaderType } from './typing'
|
||||||
|
|
||||||
|
import { runFunction } from './utils'
|
||||||
|
export default function(instance: AxiosInstance, options?: CramiHttpOptions) {
|
||||||
|
if (!instance) {
|
||||||
|
// 不存在instance
|
||||||
|
console.error('[crami] createHttp: instance is required, maybe you forgot to import {createAxios} from "@crami/http"')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
merge(app.hooks, omit(options, ['headers']))
|
||||||
|
// 处理headers
|
||||||
|
if (options?.headers) {
|
||||||
|
// 存在判断是不是一个函数
|
||||||
|
const headers = runFunction<HttpHeaderType>(options?.headers || {})
|
||||||
|
headers.then((res) => {
|
||||||
|
// 设置headers
|
||||||
|
merge(instance.defaults.headers, {
|
||||||
|
'Content-Type': ContentTypeEnum.JSON,
|
||||||
|
}, res)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
12
src/transformer/default-transform.ts
Normal file
12
src/transformer/default-transform.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import type { AxiosResponse } from 'axios'
|
||||||
|
import type { BaseApi } from '../typing'
|
||||||
|
export const defaultTransform = <R=any>(response: AxiosResponse<R>): R => {
|
||||||
|
if (response.config && response.data && response.status && response.headers && response.statusText)
|
||||||
|
return response.data
|
||||||
|
|
||||||
|
return response as any
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defaultTransformConfig = (config: BaseApi): BaseApi => {
|
||||||
|
return config
|
||||||
|
}
|
71
src/transformer/icpx-transform.ts
Normal file
71
src/transformer/icpx-transform.ts
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import type { AxiosResponse } from 'axios'
|
||||||
|
import type { BaseApi } from '../typing'
|
||||||
|
import { checkIsGet, isObject } from '../utils'
|
||||||
|
|
||||||
|
export type ICPXResponseData<D> = {
|
||||||
|
data: D
|
||||||
|
code?: number
|
||||||
|
msg?: string
|
||||||
|
success?: boolean
|
||||||
|
} & Record<string, any>
|
||||||
|
|
||||||
|
export const icpxTransform = <D>(response: AxiosResponse<D>): any => {
|
||||||
|
if (
|
||||||
|
response.config
|
||||||
|
&& response.data
|
||||||
|
&& response.status
|
||||||
|
&& response.headers
|
||||||
|
&& response.statusText
|
||||||
|
) {
|
||||||
|
const data: any = response.data
|
||||||
|
const status = response.status
|
||||||
|
if (status === 200) {
|
||||||
|
if (!data?.code) {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: 'ok',
|
||||||
|
success: true,
|
||||||
|
data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!(response as any)?.code) {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: 'ok',
|
||||||
|
success: true,
|
||||||
|
data: response,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const icpxTransformConfig = (config: BaseApi): BaseApi => {
|
||||||
|
// 判断请求方式
|
||||||
|
if (config.method && !checkIsGet(config.method)) {
|
||||||
|
if (isObject(config.params)) {
|
||||||
|
config.data = {
|
||||||
|
...(config.data || {}),
|
||||||
|
...(config.params || {}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!config.data)
|
||||||
|
config.data = config.params
|
||||||
|
}
|
||||||
|
config.params = undefined
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 如果是get请求是不是需要增加一个请求参数,防止缓存请求
|
||||||
|
const _t = Date.now()
|
||||||
|
config.params = {
|
||||||
|
_t,
|
||||||
|
...(config.params),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
}
|
2
src/transformer/index.ts
Normal file
2
src/transformer/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './default-transform'
|
||||||
|
export * from './icpx-transform'
|
42
src/typing.ts
Normal file
42
src/typing.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import type { AxiosRequestConfig, AxiosResponse } from 'axios'
|
||||||
|
|
||||||
|
export type HttpHeaderType = Record<string, any>
|
||||||
|
|
||||||
|
export interface BaseApi<D = any> extends AxiosRequestConfig<D>{
|
||||||
|
// 请求前的钩子函数
|
||||||
|
beforeRequest?: (params: any) => any
|
||||||
|
// 请求前的参数处理
|
||||||
|
beforeRequestConfig?: (config: AxiosRequestConfig) => AxiosRequestConfig
|
||||||
|
// 请求前置的query中的参数
|
||||||
|
beforeRequestQuery?: (query: any) => any
|
||||||
|
// 请求失败的钩子
|
||||||
|
onError?: (e: any) => void
|
||||||
|
// 请求接口格式化处理
|
||||||
|
urlParser?: (url: string) => string
|
||||||
|
// 请求数据格式化 同步方法,不支持Promise
|
||||||
|
responseTransform?: <R, D>(response: AxiosResponse<D>) => R
|
||||||
|
// 请求前的数据格式化 同步方法,不支持Promise
|
||||||
|
requestTransform?: <D>(config: BaseApi<D>) => BaseApi<D>
|
||||||
|
// 请求类型
|
||||||
|
dataType?: 'form'|'upload'|'json'
|
||||||
|
// 请求后的钩子函数
|
||||||
|
afterRequest?: (response: AxiosResponse) => AxiosResponse | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CramiHttpOptions{
|
||||||
|
headers?: (() => HttpHeaderType)|HttpHeaderType
|
||||||
|
// 请求前的钩子函数
|
||||||
|
beforeRequest?: (params: any) => any
|
||||||
|
// 请求前的参数处理
|
||||||
|
beforeRequestConfig?: (config: AxiosRequestConfig) => AxiosRequestConfig
|
||||||
|
// 请求前置的query中的参数
|
||||||
|
beforeRequestQuery?: (query: any) => any
|
||||||
|
// 请求失败的钩子
|
||||||
|
onError?: (e: any) => void
|
||||||
|
// 请求接口格式化处理
|
||||||
|
urlParser?: (url: string) => string
|
||||||
|
// 请求数据格式化 同步方法,不支持Promise
|
||||||
|
responseTransform?: <R = any, D = any>(response: AxiosResponse<D>) => R
|
||||||
|
// 请求前的数据格式化 同步方法,不支持Promise
|
||||||
|
requestTransform?: <D>(config: BaseApi<D>) => BaseApi<D>
|
||||||
|
}
|
36
src/utils.ts
Normal file
36
src/utils.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import type { Method } from 'axios'
|
||||||
|
|
||||||
|
export const isPromise = (value: any): value is Promise<any> => {
|
||||||
|
return value && typeof value.then === 'function' && typeof value.catch === 'function'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isObject = (value: unknown): value is object => Object.prototype.toString.call(value) === '[Object Object]'
|
||||||
|
|
||||||
|
export const isArray = (value: unknown): value is any[] => Array.isArray(value)
|
||||||
|
|
||||||
|
export const isString = (value: unknown): value is string => typeof value === 'string'
|
||||||
|
|
||||||
|
export const isFunction = (value: any): value is Function => typeof value === 'function'
|
||||||
|
|
||||||
|
export const runFunction = async<T>(fn: any, ...args: any[]): Promise<T> => {
|
||||||
|
if (!isFunction(fn))
|
||||||
|
return fn
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
const result = fn(...args)
|
||||||
|
if (isPromise(result))
|
||||||
|
return await result
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export const checkParams = <T>(checkerParams: T, defaultParams: T): T => checkerParams ?? defaultParams
|
||||||
|
|
||||||
|
export const checkIsGet = (method?: Method | string|any): boolean => method === 'get' || method === 'GET' || method === undefined || method === null
|
||||||
|
|
||||||
|
export const checkContentType = (headers: Record<string, any>): boolean => {
|
||||||
|
if (Reflect.get(headers || {}, 'content-type'))
|
||||||
|
return true
|
||||||
|
else if (Reflect.get(headers || {}, 'Content-Type'))
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
}
|
8
tsconfig.config.json
Normal file
8
tsconfig.config.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "@vue/tsconfig/tsconfig.node.json",
|
||||||
|
"include": ["./playground/vite.config.*", "vitest.config.*", "cypress.config.*"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"types": ["node"]
|
||||||
|
}
|
||||||
|
}
|
17
tsconfig.json
Normal file
17
tsconfig.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"extends": "@vue/tsconfig/tsconfig.web.json",
|
||||||
|
"include": ["./playground/src/*", "./playground/src/env.d.ts", "./playground/src/**/*.vue"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@crami/http":["./src/index.ts"],
|
||||||
|
"~/*": ["./playground/src/*"],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.config.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user