create-bubbles 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/template-react-rsbuild-biome/.prettierrc +1 -2
- package/template-react-rsbuild-biome/.vscode/settings.json +6 -10
- package/template-react-rsbuild-biome/biome.json +17 -5
- package/template-react-rsbuild-biome/package.json +22 -22
- package/template-react-rsbuild-biome/rsbuild.config.ts +2 -2
- package/template-react-rsbuild-biome/src/App.tsx +5 -6
- package/template-react-rsbuild-biome/src/index.tsx +1 -3
- package/template-react-rsbuild-biome/src/pages/home/index.tsx +1 -1
- package/template-react-rsbuild-biome/src/styles/index.scss +2 -1
- package/template-react-rsbuild-biome/src/utils/request/core/index.ts +166 -0
- package/template-react-rsbuild-biome/src/utils/request/core/utils.ts +38 -0
- package/template-react-rsbuild-biome/src/utils/request/index.ts +34 -68
- package/template-react-rsbuild-biome/uno.config.ts +3 -5
- package/template-vue-rolldown-oxc/.env +1 -3
- package/template-vue-rolldown-oxc/.env.development +1 -0
- package/template-vue-rolldown-oxc/.env.production +1 -0
- package/template-vue-rolldown-oxc/.prettierignore +34 -0
- package/template-vue-rolldown-oxc/package.json +17 -15
- package/template-vue-rolldown-oxc/src/main.ts +4 -6
- package/template-vue-rolldown-oxc/src/store/modules/user.ts +17 -0
- package/template-vue-rolldown-oxc/src/types/auto-import.d.ts +3 -1
- package/template-vue-rolldown-oxc/src/utils/env.ts +8 -3
- package/template-vue-rolldown-oxc/src/utils/request/core/index.ts +166 -0
- package/template-vue-rolldown-oxc/src/utils/request/core/utils.ts +38 -0
- package/template-vue-rolldown-oxc/src/utils/request/index.ts +41 -0
- package/template-vue-rolldown-oxc/vite.config.ts +2 -0
- package/template-vue-rsbuild-biome/.env +4 -2
- package/template-vue-rsbuild-biome/.env.development +1 -0
- package/template-vue-rsbuild-biome/.env.production +1 -0
- package/template-vue-rsbuild-biome/.vscode/settings.json +6 -0
- package/template-vue-rsbuild-biome/biome.json +3 -4
- package/template-vue-rsbuild-biome/package.json +14 -11
- package/template-vue-rsbuild-biome/rsbuild.config.ts +0 -1
- package/template-vue-rsbuild-biome/src/index.ts +0 -2
- package/template-vue-rsbuild-biome/src/utils/env.ts +10 -0
- package/template-vue-rsbuild-biome/src/utils/request/core/index.ts +166 -0
- package/template-vue-rsbuild-biome/src/utils/request/core/utils.ts +38 -0
- package/template-vue-rsbuild-biome/src/utils/request/index.ts +31 -69
- package/template-vue-rsbuild-biome/tsconfig.json +1 -1
- package/template-react-rsbuild-biome/src/utils/request/axios.ts +0 -83
- package/template-vue-rolldown-oxc/postcss.config.js +0 -5
- package/template-vue-rsbuild-biome/src/utils/request/axios.ts +0 -83
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ Available templates:
|
|
|
11
11
|
${s.vue(`vue-rsbuild-biome vue`)}
|
|
12
12
|
${s.vue(`vue-rolldown-oxc vue`)}
|
|
13
13
|
${s.react(`react-rsbuild-biome react`)}
|
|
14
|
-
${s.react(`react-rolldown-oxc react`)}`,d=e=>e.trim().replace(/\/+$/g,``),f=e=>{if(!e)return;let t=e.split(` `)[0].split(`/`);return{name:t[0],version:t[1]}},p=t=>{let n=e.readdirSync(t);return n.length===0||n.length===1&&n[0]===`.git`},m=async n=>{await Promise.all(e.readdirSync(n).filter(e=>e!==`.git`).map(r=>e.promises.rm(t.resolve(n,r),{recursive:!0,force:!0})))},h=e=>/^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test(e),g=e=>e.trim().toLowerCase().replace(/\s+/g,`-`).replace(/^[._]/,``).replace(/[^a-z\d\-~]+g/,`-`),_=[{name:`vue`,display:`Vue`,color:s.vue,variants:[{name:`vue-rsbuild-biome`,display:`rsbuild + biome`,color:s.vue},{name:`vue-rolldown-oxc`,display:`rolldown + oxc`,color:s.vue}]},{name:`react`,display:`React`,color:s.react,variants:[{name:`react-rsbuild-biome`,display:`rsbuild-biome`,color:s.react}]},{name:`others`,display:`Others`,color:s.others,variants:[{name:`create-eletron-vite`,display:`Electron ↗`,color:s.others,customCommand:`pnpm create electron-vite@latest TARGET_DIR`}]}],v=_.map(e=>e.variants.map(e=>`${e.name}`)).reduce((e,t)=>e.concat(t),[]),y=(e,t)=>{console.log(`💦customCommand`,e,t);let n=t?t.name:`npm`,r=n===`yarn`&&t?.version.startsWith(`1.`);return e.replace(/^npm create (?:-- )?/,()=>n===`bun`?`bun x create-`:n===`pnpm`?`pnpm create `:e.startsWith(`npm create -- `)?`${n} create -- `:`${n} create `).replace(`@latest`,()=>r?``:`@latest`).replace(/^npm exec/,()=>n===`pnpm`?`pnpm dlx`:n===`yarn`&&!r?`yarn dlx`:n===`bun`?`bun x`:`npm exec`)},b={_gitignore:`.gitignore`},x=(n,r)=>{e.mkdirSync(r,{recursive:!0});for(let i of e.readdirSync(n))
|
|
14
|
+
${s.react(`react-rolldown-oxc react`)}`,d=e=>e.trim().replace(/\/+$/g,``),f=e=>{if(!e)return;let t=e.split(` `)[0].split(`/`);return{name:t[0],version:t[1]}},p=t=>{let n=e.readdirSync(t);return n.length===0||n.length===1&&n[0]===`.git`},m=async n=>{await Promise.all(e.readdirSync(n).filter(e=>e!==`.git`).map(r=>e.promises.rm(t.resolve(n,r),{recursive:!0,force:!0})))},h=e=>/^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test(e),g=e=>e.trim().toLowerCase().replace(/\s+/g,`-`).replace(/^[._]/,``).replace(/[^a-z\d\-~]+g/,`-`),_=[{name:`vue`,display:`Vue`,color:s.vue,variants:[{name:`vue-rsbuild-biome`,display:`rsbuild + biome`,color:s.vue},{name:`vue-rolldown-oxc`,display:`rolldown + oxc`,color:s.vue}]},{name:`react`,display:`React`,color:s.react,variants:[{name:`react-rsbuild-biome`,display:`rsbuild-biome`,color:s.react}]},{name:`others`,display:`Others`,color:s.others,variants:[{name:`create-eletron-vite`,display:`Electron ↗`,color:s.others,customCommand:`pnpm create electron-vite@latest TARGET_DIR`}]}],v=_.map(e=>e.variants.map(e=>`${e.name}`)).reduce((e,t)=>e.concat(t),[]),y=(e,t)=>{console.log(`💦customCommand`,e,t);let n=t?t.name:`npm`,r=n===`yarn`&&t?.version.startsWith(`1.`);return e.replace(/^npm create (?:-- )?/,()=>n===`bun`?`bun x create-`:n===`pnpm`?`pnpm create `:e.startsWith(`npm create -- `)?`${n} create -- `:`${n} create `).replace(`@latest`,()=>r?``:`@latest`).replace(/^npm exec/,()=>n===`pnpm`?`pnpm dlx`:n===`yarn`&&!r?`yarn dlx`:n===`bun`?`bun x`:`npm exec`)},b={_gitignore:`.gitignore`},x=(n,r)=>{e.mkdirSync(r,{recursive:!0});for(let i of e.readdirSync(n))S(t.resolve(n,i),t.resolve(r,i))},S=(t,n)=>{e.statSync(t).isDirectory()?x(t,n):e.copyFileSync(t,n)},C=(t,n)=>{let r=e.readFileSync(t,`utf-8`);e.writeFileSync(t,n(r),`utf-8`)},w=(e,n)=>{C(t.resolve(e,`package.json`),e=>e.replace(/"@vitejs\/plugin-react": ".+?"/,`"@vitejs/plugin-react-swc": "^4.0.1"`)),C(t.resolve(e,`vite.config.${n?`ts`:`js`}`),e=>e.replace(`@vitejs/plugin-react`,`@vitejs/plugin-react-swc`))};(async()=>{console.log(c);let i=c._[0]?d(c._[0]):void 0,x=c.template,C=c.overwrite,T=`bubbles-project`;if(c.help){console.log(u);return}let E=f(process.env.npm_config_user_agent),D=()=>n.cancel(`Operation cancelled`),O=i;if(!O){let e=await n.text({message:`Project name`,defaultValue:T,placeholder:T,validate:e=>e.length===0||d(e).length>0?void 0:`Invalid project name`});if(n.isCancel(e))return D();O=d(e)}if(e.existsSync(O)&&!p(O)){let e=C?`yes`:await n.select({message:O===`.`?`Current directory`:`Target directory "${O}" is not empty. Please choose how to proceed:`,options:[{label:`${s.vue(`Cancel operation`)}`,value:`no`},{label:`Remove existing files and continue`,value:`yes`},{label:`Ignore files and continue`,value:`ignore`}]});if(n.isCancel(e))return D();switch(e){case`yes`:m(O);break;case`no`:D();return}}let k=t.basename(t.resolve(O));if(!h(k)){let e=await n.text({message:`Package name is invalid. please input again:`,defaultValue:g(k),placeholder:g(k),validate(e){if(!h(e))return`Invalid package.json name`}});if(n.isCancel(e))return D();k=e}let A=x,j=!1;if(x&&!v.includes(x)&&(A=void 0,j=!0),!A){let e=await n.select({message:j?`"${x}" isn't a valia template. please choose from below:`:`Select a framework`,options:_.map(e=>{let t=e.color;return{label:t(e.display),value:e}})});if(n.isCancel(e))return D();console.log(`💦pkgInfo`,E);let t=await n.select({message:`Select a variant:`,options:e.variants.map(e=>{let t=e.color,n=e.customCommand?y(e.customCommand,E).replace(/ TARGET_DIR$/,``):void 0;return{label:t(e.display||e.name),value:e.name,hint:n}})});if(n.isCancel(t))return D();A=t}let M=t.join(l,O);e.mkdirSync(M,{recursive:!0});let N=!1;A.includes(`-swc`)&&(N=!0,A=A.replace(`-swc`,``));let P=E?E.name:`npm`,{customCommand:F}=_.flatMap(e=>e.variants).find(e=>e.name===A)??{};if(F){let[e,...t]=y(F,E).split(` `),n=t.map(e=>e.replace(`TARGET_DIR`,()=>O));console.log(`💦replacedArgs`,n);let{status:r}=a.sync(e,n,{stdio:`inherit`});process.exit(r??0)}n.log.step(`scaffolding project in ${M}...`);let I=t.resolve(o(import.meta.url),`../..`,`template-${A}`),L=(n,r)=>{let i=t.join(M,b[n]??n);r?e.writeFileSync(i,r):S(t.join(I,n),i)},R=e.readdirSync(I);for(let e of R)e!==`package.json`&&L(e);let z=JSON.parse(e.readFileSync(t.join(I,`package.json`),`utf-8`));z.name=k,L(`package.json`,`${JSON.stringify(z,null,2)}\n`),N&&w(M,A.endsWith(`-ts`));let B=``,V=t.relative(l,M);switch(console.log(`💦cwd`,l),console.log(`💦root`,M),console.log(`💦cdProjectName`,V),B+=`Done. Now run:
|
|
15
15
|
`,M!==l&&(B+=`\n cd ${V.includes(` `)?`"${V}"`:V} `),P){case`yarn`:B+=`
|
|
16
16
|
yarn`,B+=`
|
|
17
17
|
yarn dev`;break;default:B+=r([`pink`,`white`])(`\n ${P} install`),B+=r([`pink`,`white`])(`\n ${P} run dev`);break}n.outro(B)})().catch(e=>{console.error(`💦`,e)});export{};
|
package/package.json
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"editor.formatOnSave": true,
|
|
3
|
-
"editor.defaultFormatter": "biomejs.biome",
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
"explorer.fileNesting.patterns": {
|
|
7
|
-
"*.ts": "$(capture).test.ts, $(capture).test.tsx",
|
|
8
|
-
"*.tsx": "$(capture).test.ts, $(capture).test.tsx",
|
|
9
|
-
"*.env": "$(capture).env.*",
|
|
10
|
-
"package.json": "pnpm-lock.yaml",
|
|
11
|
-
".prettierrc": ".prettierignore"
|
|
3
|
+
"editor.defaultFormatter": "biomejs.biome",
|
|
4
|
+
"editor.codeActionsOnSave": {
|
|
5
|
+
"source.fixAll.biome": "explicit"
|
|
12
6
|
},
|
|
13
|
-
"
|
|
7
|
+
"[less]": {
|
|
8
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
9
|
+
}
|
|
14
10
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
|
|
3
3
|
"files": {
|
|
4
|
-
"ignoreUnknown": true
|
|
4
|
+
"ignoreUnknown": true,
|
|
5
|
+
"includes": ["**", "!public/**/*", "!node_modules/**/*", "!dist/**/*"]
|
|
5
6
|
},
|
|
6
7
|
"formatter": {
|
|
7
8
|
"enabled": true,
|
|
@@ -54,9 +55,7 @@
|
|
|
54
55
|
"useAriaPropsForRole": "off",
|
|
55
56
|
"useValidAnchor": "off"
|
|
56
57
|
},
|
|
57
|
-
"nursery":
|
|
58
|
-
"useUniqueElementIds": "off"
|
|
59
|
-
}
|
|
58
|
+
"nursery": "off"
|
|
60
59
|
}
|
|
61
60
|
},
|
|
62
61
|
"css": {
|
|
@@ -75,7 +74,20 @@
|
|
|
75
74
|
"enabled": true,
|
|
76
75
|
"actions": {
|
|
77
76
|
"source": {
|
|
78
|
-
"organizeImports":
|
|
77
|
+
"organizeImports": {
|
|
78
|
+
"level": "on",
|
|
79
|
+
"options": {
|
|
80
|
+
"identifierOrder": "natural",
|
|
81
|
+
"groups": [
|
|
82
|
+
[":NODE:", ":BUN:"],
|
|
83
|
+
":BLANK_LINE:",
|
|
84
|
+
["react", "react-dom/**", "react-dom", "react-router", "react-router-dom"],
|
|
85
|
+
["vue", "vue-router"],
|
|
86
|
+
":BLANK_LINE:",
|
|
87
|
+
["@/**", "**"]
|
|
88
|
+
]
|
|
89
|
+
}
|
|
90
|
+
}
|
|
79
91
|
}
|
|
80
92
|
}
|
|
81
93
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "
|
|
2
|
+
"name": "bubbles-project",
|
|
3
3
|
"private": true,
|
|
4
4
|
"version": "1.0.0",
|
|
5
5
|
"scripts": {
|
|
@@ -12,31 +12,31 @@
|
|
|
12
12
|
"reinstall": "rimraf pnpm-lock.yaml && rimraf node_modules && pnpm install"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
+
"@alova/adapter-axios": "^2.0.16",
|
|
15
16
|
"@ant-design/icons-vue": "^7.0.1",
|
|
16
|
-
"ahooks": "^3.9.
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"dayjs": "^1.11.
|
|
20
|
-
"react": "^19.
|
|
21
|
-
"react-dom": "^19.
|
|
22
|
-
"react-router": "^7.
|
|
23
|
-
"zustand": "^5.0.
|
|
17
|
+
"ahooks": "^3.9.5",
|
|
18
|
+
"alova": "^3.3.4",
|
|
19
|
+
"antd": "^5.27.5",
|
|
20
|
+
"dayjs": "^1.11.18",
|
|
21
|
+
"react": "^19.2.0",
|
|
22
|
+
"react-dom": "^19.2.0",
|
|
23
|
+
"react-router": "^7.9.4",
|
|
24
|
+
"zustand": "^5.0.8"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|
|
26
|
-
"@biomejs/biome": "^2.
|
|
27
|
-
"@commitlint/config-conventional": "^
|
|
28
|
-
"@
|
|
29
|
-
"@rsbuild/
|
|
30
|
-
"@rsbuild/plugin-
|
|
31
|
-
"@rsbuild/plugin-sass": "^1.3.5",
|
|
27
|
+
"@biomejs/biome": "^2.2.6",
|
|
28
|
+
"@commitlint/config-conventional": "^20.0.0",
|
|
29
|
+
"@rsbuild/core": "^1.5.17",
|
|
30
|
+
"@rsbuild/plugin-react": "^1.4.1",
|
|
31
|
+
"@rsbuild/plugin-sass": "^1.4.0",
|
|
32
32
|
"@rsbuild/plugin-svgr": "^1.2.2",
|
|
33
|
-
"@types/react": "^19.
|
|
34
|
-
"@types/react-dom": "^19.
|
|
35
|
-
"@unocss/postcss": "66.4
|
|
36
|
-
"lefthook": "^1.
|
|
33
|
+
"@types/react": "^19.2.2",
|
|
34
|
+
"@types/react-dom": "^19.2.2",
|
|
35
|
+
"@unocss/postcss": "^66.5.4",
|
|
36
|
+
"lefthook": "^1.13.6",
|
|
37
37
|
"prettier": "^3.6.2",
|
|
38
|
-
"typescript": "^5.9.
|
|
39
|
-
"unocss": "66.4
|
|
40
|
-
"unplugin-auto-import": "^20.
|
|
38
|
+
"typescript": "^5.9.3",
|
|
39
|
+
"unocss": "^66.5.4",
|
|
40
|
+
"unplugin-auto-import": "^20.2.0"
|
|
41
41
|
}
|
|
42
42
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { defineConfig } from '@rsbuild/core'
|
|
2
2
|
import { pluginReact } from '@rsbuild/plugin-react'
|
|
3
|
-
import AutoImport from 'unplugin-auto-import/rspack'
|
|
4
|
-
import UnoCSS from '@unocss/postcss'
|
|
5
3
|
import { pluginSass } from '@rsbuild/plugin-sass'
|
|
6
4
|
import { pluginSvgr } from '@rsbuild/plugin-svgr'
|
|
5
|
+
import UnoCSS from '@unocss/postcss'
|
|
6
|
+
import AutoImport from 'unplugin-auto-import/rspack'
|
|
7
7
|
|
|
8
8
|
export default defineConfig({
|
|
9
9
|
html: {
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { RouterProvider } from 'react-router'
|
|
2
|
-
|
|
3
|
-
import router from './router';
|
|
1
|
+
import { RouterProvider } from 'react-router'
|
|
2
|
+
import router from './router'
|
|
4
3
|
|
|
5
4
|
const App = () => {
|
|
6
|
-
return <RouterProvider router={router}
|
|
7
|
-
}
|
|
5
|
+
return <RouterProvider router={router} />
|
|
6
|
+
}
|
|
8
7
|
|
|
9
|
-
export default App
|
|
8
|
+
export default App
|
|
@@ -2,10 +2,8 @@ import React, { Suspense } from 'react'
|
|
|
2
2
|
import ReactDOM from 'react-dom/client'
|
|
3
3
|
|
|
4
4
|
import App from './App'
|
|
5
|
-
|
|
6
|
-
import '@/styles/index.scss'
|
|
7
|
-
|
|
8
5
|
import Loading from './components/Loading/PageLoading'
|
|
6
|
+
import '@/styles/index.scss'
|
|
9
7
|
|
|
10
8
|
const rootEl = document.getElementById('root')
|
|
11
9
|
if (rootEl) {
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { type AlovaGenerics, type AlovaOptions, createAlova } from 'alova'
|
|
2
|
+
import { deepMergeObject, isReadableStream } from './utils'
|
|
3
|
+
import adapterFetch from 'alova/fetch'
|
|
4
|
+
|
|
5
|
+
interface statusMap {
|
|
6
|
+
success?: number
|
|
7
|
+
unAuthorized?: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface codeMap {
|
|
11
|
+
success?: number[]
|
|
12
|
+
unAuthorized?: number[]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface baseRequestOption<AG extends AlovaGenerics> {
|
|
16
|
+
baseUrl?: string
|
|
17
|
+
timeout?: number
|
|
18
|
+
commonHeaders?: Record<string, string | (() => string)>
|
|
19
|
+
statusMap?: statusMap
|
|
20
|
+
codeMap?: codeMap
|
|
21
|
+
responseDataKey?: string
|
|
22
|
+
responseMessageKey?: string
|
|
23
|
+
isTransformResponse?: boolean
|
|
24
|
+
isShowSuccessMessage?: boolean
|
|
25
|
+
successDefaultMessage?: string
|
|
26
|
+
isShowErrorMessage?: boolean
|
|
27
|
+
errorDefaultMessage?: string
|
|
28
|
+
statesHook?: AlovaOptions<AG>['statesHook']
|
|
29
|
+
successMessageFunc?: (message: string) => void
|
|
30
|
+
errorMessageFunc?: (message: string) => void
|
|
31
|
+
unAuthorizedResponseFunc?: () => void
|
|
32
|
+
requestAdapter?: AlovaOptions<AG>['requestAdapter']
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface CustomConfig {
|
|
36
|
+
isTransformResponse?: boolean
|
|
37
|
+
isShowSuccessMessage?: boolean
|
|
38
|
+
isShowErrorMessage?: boolean
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type requestOption = baseRequestOption<AlovaGenerics> & CustomConfig
|
|
42
|
+
|
|
43
|
+
export const createInstance = (option: requestOption) => {
|
|
44
|
+
const defaultOption: requestOption = {
|
|
45
|
+
baseUrl: '/',
|
|
46
|
+
timeout: 0,
|
|
47
|
+
statusMap: {
|
|
48
|
+
success: 200,
|
|
49
|
+
unAuthorized: 401,
|
|
50
|
+
},
|
|
51
|
+
codeMap: {
|
|
52
|
+
success: [200],
|
|
53
|
+
unAuthorized: [401],
|
|
54
|
+
},
|
|
55
|
+
responseDataKey: 'data',
|
|
56
|
+
responseMessageKey: 'message',
|
|
57
|
+
isTransformResponse: true,
|
|
58
|
+
isShowSuccessMessage: false,
|
|
59
|
+
successDefaultMessage: '操作成功',
|
|
60
|
+
isShowErrorMessage: true,
|
|
61
|
+
errorDefaultMessage: '服务异常',
|
|
62
|
+
requestAdapter: adapterFetch(),
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const mergeOption: baseRequestOption<AlovaGenerics> & CustomConfig = deepMergeObject(
|
|
66
|
+
defaultOption,
|
|
67
|
+
option,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
const instance = createAlova({
|
|
71
|
+
baseURL: mergeOption.baseUrl,
|
|
72
|
+
timeout: mergeOption.timeout,
|
|
73
|
+
statesHook: mergeOption?.statesHook,
|
|
74
|
+
requestAdapter: mergeOption.requestAdapter as AlovaOptions<AlovaGenerics>['requestAdapter'],
|
|
75
|
+
beforeRequest: async (method) => {
|
|
76
|
+
for (const [key, value] of Object.entries(option?.commonHeaders ?? {})) {
|
|
77
|
+
method.config.headers[key] = typeof value === 'function' ? value() : value
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
responded: {
|
|
81
|
+
onSuccess: async (response) => {
|
|
82
|
+
if (!mergeOption?.isTransformResponse) return response
|
|
83
|
+
const { status } = response
|
|
84
|
+
|
|
85
|
+
// 判断响应类型:如果使用 adapterFetch,response.data 是可读流,则调用 json();否则直接使用 response.data
|
|
86
|
+
const data =
|
|
87
|
+
response?.body && isReadableStream(response.body)
|
|
88
|
+
? await response.json() // adapterFetch 的响应,使用 json() 解析可读流
|
|
89
|
+
: response.data // 其他适配器的响应
|
|
90
|
+
// 不成功的情况
|
|
91
|
+
if (status !== mergeOption.statusMap?.success) {
|
|
92
|
+
// 如果后端使用status 字段来表示未授权,则返回401
|
|
93
|
+
if (mergeOption?.statusMap?.unAuthorized === status) {
|
|
94
|
+
mergeOption?.unAuthorizedResponseFunc?.()
|
|
95
|
+
}
|
|
96
|
+
return Promise.reject(response)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const {
|
|
100
|
+
responseDataKey,
|
|
101
|
+
codeMap,
|
|
102
|
+
isShowSuccessMessage,
|
|
103
|
+
responseMessageKey,
|
|
104
|
+
isShowErrorMessage,
|
|
105
|
+
} = mergeOption
|
|
106
|
+
const {
|
|
107
|
+
code,
|
|
108
|
+
[responseDataKey as string]: responseData,
|
|
109
|
+
[responseMessageKey as string]: responseMessage,
|
|
110
|
+
} = data
|
|
111
|
+
if (!codeMap?.success?.includes(+code)) {
|
|
112
|
+
// code unAuthorized 处理
|
|
113
|
+
if (codeMap?.unAuthorized?.includes(+code)) {
|
|
114
|
+
mergeOption?.unAuthorizedResponseFunc?.()
|
|
115
|
+
return Promise.reject(response)
|
|
116
|
+
}
|
|
117
|
+
// 其他错误直接打印msg
|
|
118
|
+
|
|
119
|
+
const errorMessage = data[responseMessageKey as string] ?? mergeOption.errorDefaultMessage
|
|
120
|
+
if (isShowErrorMessage) mergeOption?.errorMessageFunc?.(errorMessage)
|
|
121
|
+
return Promise.reject(response)
|
|
122
|
+
}
|
|
123
|
+
if (isShowSuccessMessage)
|
|
124
|
+
mergeOption?.successMessageFunc?.(responseMessage ?? mergeOption.successDefaultMessage)
|
|
125
|
+
return responseData
|
|
126
|
+
},
|
|
127
|
+
onError: (error) => {
|
|
128
|
+
if (mergeOption?.isShowErrorMessage)
|
|
129
|
+
mergeOption.errorMessageFunc?.(
|
|
130
|
+
error.response?.data?.message ?? mergeOption?.errorDefaultMessage,
|
|
131
|
+
)
|
|
132
|
+
},
|
|
133
|
+
// onComplete: (_method) => {},
|
|
134
|
+
},
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
return instance
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 🚀 创建双重调用实例的工厂函数
|
|
141
|
+
export const createDualCallInstance = (baseConfig: baseRequestOption<AlovaGenerics>) => {
|
|
142
|
+
// 创建默认实例
|
|
143
|
+
const defaultInstance = createInstance(baseConfig)
|
|
144
|
+
|
|
145
|
+
// 双重调用函数
|
|
146
|
+
const dualInstance = (option?: CustomConfig) => {
|
|
147
|
+
if (option) {
|
|
148
|
+
// 合并配置并创建新实例
|
|
149
|
+
const mergedConfig = { ...baseConfig, ...option }
|
|
150
|
+
return createInstance(mergedConfig)
|
|
151
|
+
}
|
|
152
|
+
return defaultInstance
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// 🎯 直接绑定 HTTP 方法,无需复杂类型注释
|
|
156
|
+
dualInstance.Get = defaultInstance.Get.bind(defaultInstance)
|
|
157
|
+
dualInstance.Post = defaultInstance.Post.bind(defaultInstance)
|
|
158
|
+
dualInstance.Put = defaultInstance.Put.bind(defaultInstance)
|
|
159
|
+
dualInstance.Delete = defaultInstance.Delete.bind(defaultInstance)
|
|
160
|
+
dualInstance.Patch = defaultInstance.Patch.bind(defaultInstance)
|
|
161
|
+
dualInstance.Head = defaultInstance.Head.bind(defaultInstance)
|
|
162
|
+
dualInstance.Options = defaultInstance.Options.bind(defaultInstance)
|
|
163
|
+
dualInstance.Request = defaultInstance.Request.bind(defaultInstance)
|
|
164
|
+
|
|
165
|
+
return dualInstance
|
|
166
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export const deepMergeObject = <T = any>(source: T, target: Partial<T>): T => {
|
|
2
|
+
const isObject = (obj: any): obj is Record<string, any> =>
|
|
3
|
+
obj && typeof obj === 'object' && !Array.isArray(obj)
|
|
4
|
+
|
|
5
|
+
const merge = (src: any, tgt: any): any => {
|
|
6
|
+
if (isObject(src) && isObject(tgt)) {
|
|
7
|
+
Object.keys(tgt).forEach((key) => {
|
|
8
|
+
if (isObject(tgt[key])) {
|
|
9
|
+
src[key] = merge(src[key] || {}, tgt[key])
|
|
10
|
+
} else {
|
|
11
|
+
src[key] = tgt[key]
|
|
12
|
+
}
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
return src
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return merge({ ...source }, target)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 判断一个变量是不是可读流
|
|
23
|
+
* @param data
|
|
24
|
+
*/
|
|
25
|
+
export const isReadableStream = (data: unknown): boolean => {
|
|
26
|
+
if (!(data instanceof ReadableStream)) {
|
|
27
|
+
return false
|
|
28
|
+
}
|
|
29
|
+
if (typeof data.locked !== 'boolean') return false
|
|
30
|
+
|
|
31
|
+
const instanceFunc = ['cancel', 'getReader', 'pipeThrough', 'pipeTo', 'tee'] as const
|
|
32
|
+
|
|
33
|
+
for (const func of instanceFunc) {
|
|
34
|
+
if (typeof data[func] !== 'function') return false
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return true
|
|
38
|
+
}
|
|
@@ -1,77 +1,43 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { envVariables } from '../env'
|
|
2
|
+
import { createDualCallInstance } from './core'
|
|
3
|
+
import { router } from '@/router'
|
|
4
|
+
import { message } from 'antd'
|
|
5
|
+
import 'element-plus/es/components/message/style/css'
|
|
6
|
+
import vueHook from 'alova/vue'
|
|
7
|
+
import { axiosRequestAdapter } from '@alova/adapter-axios'
|
|
2
8
|
|
|
3
|
-
|
|
9
|
+
// 🎯 获取基础配置
|
|
10
|
+
const getBaseConfig = (): Parameters<typeof createDualCallInstance>[0] => {
|
|
4
11
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
config?: AxiosRequestConfig<any>
|
|
12
|
+
return {
|
|
13
|
+
baseUrl: `/${envVariables.PUBLIC_API_AFFIX}`,
|
|
14
|
+
statusMap: {
|
|
15
|
+
success: 200,
|
|
16
|
+
unAuthorized: 401,
|
|
11
17
|
},
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
post: <T = any>(
|
|
15
|
-
config: {
|
|
16
|
-
url: string
|
|
17
|
-
data?: AxiosRequestConfig['data']
|
|
18
|
-
params?: AxiosRequestConfig['params']
|
|
19
|
-
config?: AxiosRequestConfig<any>
|
|
18
|
+
codeMap: {
|
|
19
|
+
success: [200],
|
|
20
20
|
},
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
config: {
|
|
25
|
-
url: string
|
|
26
|
-
data?: AxiosRequestConfig['data']
|
|
27
|
-
config?: AxiosRequestConfig<any>
|
|
21
|
+
responseDataKey: 'data',
|
|
22
|
+
responseMessageKey: 'msg',
|
|
23
|
+
commonHeaders: {
|
|
28
24
|
},
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
delete: <T = any>(
|
|
32
|
-
config: {
|
|
33
|
-
url: string
|
|
34
|
-
data?: AxiosRequestConfig['data']
|
|
35
|
-
config?: AxiosRequestConfig<any>
|
|
25
|
+
successMessageFunc: (msg: string) => {
|
|
26
|
+
message.success(msg)
|
|
36
27
|
},
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const createAxios: createAxiosType = {
|
|
42
|
-
get: (config, option) =>
|
|
43
|
-
request(option).get(config.url, {
|
|
44
|
-
params: config.params,
|
|
45
|
-
...config?.config,
|
|
46
|
-
}),
|
|
47
|
-
post: (
|
|
48
|
-
config: {
|
|
49
|
-
url: string
|
|
50
|
-
params?: Record<string, string>
|
|
51
|
-
data?: any
|
|
52
|
-
config?: AxiosRequestConfig<any>
|
|
28
|
+
errorMessageFunc: (msg: string) => {
|
|
29
|
+
message.error(msg)
|
|
53
30
|
},
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const [key, value] = entries[i]
|
|
62
|
-
url += `${key}=${value}${i < entries.length - 1 ? '&' : ''}`
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return request(option).post(url, config?.data, config?.config)
|
|
66
|
-
},
|
|
67
|
-
put: (
|
|
68
|
-
config: { url: string; data?: any; config?: AxiosRequestConfig<any> },
|
|
69
|
-
option?: CustomConfig,
|
|
70
|
-
) => request(option).put(config.url, config?.data, config?.config),
|
|
71
|
-
delete: (
|
|
72
|
-
config: { url: string; config?: AxiosRequestConfig<any> },
|
|
73
|
-
customConfig?: CustomConfig,
|
|
74
|
-
) => request(customConfig).delete(config.url, config?.config),
|
|
31
|
+
unAuthorizedResponseFunc: () => {
|
|
32
|
+
router.navigate('/login')
|
|
33
|
+
message.error('登录过期或未登录')
|
|
34
|
+
},
|
|
35
|
+
statesHook: vueHook,
|
|
36
|
+
requestAdapter: axiosRequestAdapter(),
|
|
37
|
+
}
|
|
75
38
|
}
|
|
76
39
|
|
|
77
|
-
|
|
40
|
+
// 🚀 使用 alova-core 的双重调用功能,超级简洁!
|
|
41
|
+
const alovaRequest = createDualCallInstance(getBaseConfig())
|
|
42
|
+
|
|
43
|
+
export default alovaRequest
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { defineConfig,
|
|
1
|
+
import { defineConfig, presetUno } from 'unocss'
|
|
2
2
|
|
|
3
3
|
export default defineConfig({
|
|
4
4
|
content: {
|
|
5
|
-
filesystem: ['
|
|
5
|
+
filesystem: ['./src/**/*.{html,js,ts,jsx,tsx}'],
|
|
6
6
|
},
|
|
7
|
-
presets: [
|
|
8
|
-
rules: [],
|
|
9
|
-
shortcuts: [['flex-center', 'flex items-center justify-center']],
|
|
7
|
+
presets: [presetUno()],
|
|
10
8
|
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
PUBLIC_API_URL = 'http://localhost:8080'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
PUBLIC_API_URL = 'http://localhost:8080'
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
**/*.png
|
|
2
|
+
**/*.svg
|
|
3
|
+
CODEOWNERS
|
|
4
|
+
.dockerignore
|
|
5
|
+
Dockerfile.ui-test
|
|
6
|
+
.dumi/tmp
|
|
7
|
+
.dumi/tmp-production
|
|
8
|
+
!dumi
|
|
9
|
+
# AUTHORS.txt
|
|
10
|
+
lib/
|
|
11
|
+
es/
|
|
12
|
+
dist/
|
|
13
|
+
# _site/
|
|
14
|
+
# server
|
|
15
|
+
# coverage/
|
|
16
|
+
# CNAME
|
|
17
|
+
LICENSE
|
|
18
|
+
yarn.lock
|
|
19
|
+
# netlify.toml
|
|
20
|
+
yarn-error.log
|
|
21
|
+
*.sh
|
|
22
|
+
*.snap
|
|
23
|
+
components/*/*.js
|
|
24
|
+
components/*/*.jsx
|
|
25
|
+
.gitignore
|
|
26
|
+
.npmignore
|
|
27
|
+
.prettierignore
|
|
28
|
+
.DS_Store
|
|
29
|
+
.editorconfig
|
|
30
|
+
.eslintignore
|
|
31
|
+
.history
|
|
32
|
+
**/*.yml
|
|
33
|
+
*.html
|
|
34
|
+
CHANGELOG.*.md
|