feat:删除 alova、openapi 依赖

feat:删除无用的 services 调用
This commit is contained in:
YunaiV
2025-12-12 19:13:58 +08:00
parent 3acee68ab9
commit 7f9eaf82a2
15 changed files with 3 additions and 371 deletions

View File

@@ -1,11 +1,9 @@
# API 和 HTTP 请求规范
## HTTP 请求封装
- 可以使用 `简单http` 或者 `alova` 或者 `@tanstack/vue-query` 进行请求管理
- 可以使用 `简单http` 进行请求管理
- HTTP 配置在 [src/http/](mdc:src/http/) 目录下
- `简单http` - [src/http/http.ts](mdc:src/http/http.ts)
- `alova` - [src/http/alova.ts](mdc:src/http/alova.ts)
- `vue-query` - [src/http/vue-query.ts](mdc:src/http/vue-query.ts)
- 请求拦截器在 [src/http/interceptor.ts](mdc:src/http/interceptor.ts)
- 支持请求重试、缓存、错误处理
@@ -13,7 +11,7 @@
- API 接口定义在 [src/api/](mdc:src/api/) 目录下
- 按功能模块组织 API 文件
- 使用 TypeScript 定义请求和响应类型
- 支持 `简单http`、`alova` 和 `vue-query` 三种请求方式
- 支持 `简单http`请求方式
## 示例代码结构
@@ -28,18 +26,6 @@ export interface LoginResponse {
token: string
userInfo: UserInfo
}
// alova 方式
export const login = (params: LoginParams) =>
http.Post<LoginResponse>('/api/login', params)
// vue-query 方式
export const useLogin = () => {
return useMutation({
mutationFn: (params: LoginParams) =>
http.post<LoginResponse>('/api/login', params)
})
}
```
## 错误处理

View File

@@ -16,7 +16,7 @@
"explorer.fileNesting.patterns": {
"README.md": "index.html,favicon.ico,robots.txt,CHANGELOG.md",
"docker.md": "Dockerfile,docker*.md,nginx*,.dockerignore",
"pages.config.ts": "manifest.config.ts,openapi-ts-request.config.ts",
"pages.config.ts": "manifest.config.ts",
"package.json": "tsconfig.json,pnpm-lock.yaml,pnpm-workspace.yaml,LICENSE,.gitattributes,.gitignore,.gitpod.yml,CNAME,.npmrc,.browserslistrc",
"eslint.config.mjs": ".commitlintrc.*,.prettier*,.editorconfig,.commitlint.cjs,.eslint*"
},

View File

@@ -1,14 +0,0 @@
import { defineConfig } from 'openapi-ts-request'
export default defineConfig([
{
describe: 'unibest-openapi-test',
schemaPath: 'https://ukw0y1.laf.run/unibest-opapi-test.json',
serversPath: './src/service',
requestLibPath: `import request from '@/http/vue-query';\n import { CustomRequestOptions_ } from '@/http/types';`,
requestOptionsType: 'CustomRequestOptions_',
isGenReactQuery: false,
reactQueryMode: 'vue',
isGenJavaScript: false,
},
])

View File

@@ -88,7 +88,6 @@
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
"build:quickapp-webview-union": "uni build -p quickapp-webview-union",
"type-check": "vue-tsc --noEmit",
"openapi": "openapi-ts",
"init-husky": "git init && husky",
"init-baseFiles": "node ./scripts/create-base-files.js",
"init-json": "pnpm init-baseFiles",
@@ -97,8 +96,6 @@
"lint:fix": "eslint --fix"
},
"dependencies": {
"@alova/adapter-uniapp": "^2.0.14",
"@alova/shared": "^1.3.1",
"@dcloudio/uni-app": "3.0.0-4070620250821001",
"@dcloudio/uni-app-harmony": "3.0.0-4070620250821001",
"@dcloudio/uni-app-plus": "3.0.0-4070620250821001",
@@ -116,7 +113,6 @@
"@dcloudio/uni-mp-xhs": "3.0.0-4070620250821001",
"@dcloudio/uni-quickapp-webview": "3.0.0-4070620250821001",
"abortcontroller-polyfill": "^1.7.8",
"alova": "^3.3.3",
"dayjs": "1.11.10",
"pinia": "2.0.36",
"pinia-plugin-persistedstate": "3.2.1",
@@ -163,7 +159,6 @@
"husky": "^9.1.7",
"lint-staged": "^15.2.10",
"miniprogram-api-typings": "^4.1.0",
"openapi-ts-request": "^1.10.0",
"postcss": "^8.4.49",
"postcss-html": "^1.8.0",
"postcss-scss": "^4.0.9",

38
pnpm-lock.yaml generated
View File

@@ -12,12 +12,6 @@ importers:
.:
dependencies:
'@alova/adapter-uniapp':
specifier: ^2.0.14
version: 2.0.14(alova@3.3.4)
'@alova/shared':
specifier: ^1.3.1
version: 1.3.1
'@dcloudio/uni-app':
specifier: 3.0.0-4070620250821001
version: 3.0.0-4070620250821001(@dcloudio/types@3.4.19)(postcss@8.5.6)(rollup@4.50.0)(vue@3.4.21(typescript@5.8.3))
@@ -69,9 +63,6 @@ importers:
abortcontroller-polyfill:
specifier: ^1.7.8
version: 1.7.8
alova:
specifier: ^3.3.3
version: 3.3.4
dayjs:
specifier: 1.11.10
version: 1.11.10
@@ -247,14 +238,6 @@ importers:
packages:
'@alova/adapter-uniapp@2.0.14':
resolution: {integrity: sha512-AHrS/evdhONySkmtYHs6Sh1D+a0+zjBeOltcYY2/az/KEPN9p/l4H9Nvy+ghLhzMzfKfnITxeeMOi5ANyERimw==}
peerDependencies:
alova: ^3.0.20
'@alova/shared@1.3.1':
resolution: {integrity: sha512-ijSOaFLUFcVzMKSY3avoEE5C03/p9atjMDPBwvNkwnzaCrhv6/m4A121NdadF8YlHCRuifyYfz90IyEdMXTsJg==}
'@ampproject/remapping@2.3.0':
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
@@ -2579,10 +2562,6 @@ packages:
alien-signals@2.0.7:
resolution: {integrity: sha512-wE7y3jmYeb0+h6mr5BOovuqhFv22O/MV9j5p0ndJsa7z1zJNPGQ4ph5pQk/kTTCWRC3xsA4SmtwmkzQO+7NCNg==}
alova@3.3.4:
resolution: {integrity: sha512-UKKqXdvf8aQ4C7m3brO77YWe5CDz8N59PdAUz7M8gowKUUXTutbk0Vk5DRBrCe0hMUyyNMUhdCZ38llGxCViyQ==}
engines: {node: '>= 18.0.0'}
ansi-escapes@4.3.2:
resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
engines: {node: '>=8'}
@@ -5302,9 +5281,6 @@ packages:
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
engines: {node: '>= 0.6'}
rate-limiter-flexible@5.0.5:
resolution: {integrity: sha512-+/dSQfo+3FYwYygUs/V2BBdwGa9nFtakDwKt4l0bnvNB53TNT++QSFewwHX9qXrZJuMe9j+TUaU21lm5ARgqdQ==}
raw-body@2.5.2:
resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
engines: {node: '>= 0.8'}
@@ -6284,13 +6260,6 @@ packages:
snapshots:
'@alova/adapter-uniapp@2.0.14(alova@3.3.4)':
dependencies:
'@alova/shared': 1.3.1
alova: 3.3.4
'@alova/shared@1.3.1': {}
'@ampproject/remapping@2.3.0':
dependencies:
'@jridgewell/gen-mapping': 0.3.13
@@ -9784,11 +9753,6 @@ snapshots:
alien-signals@2.0.7: {}
alova@3.3.4:
dependencies:
'@alova/shared': 1.3.1
rate-limiter-flexible: 5.0.5
ansi-escapes@4.3.2:
dependencies:
type-fest: 0.21.3
@@ -12987,8 +12951,6 @@ snapshots:
range-parser@1.2.1: {}
rate-limiter-flexible@5.0.5: {}
raw-body@2.5.2:
dependencies:
bytes: 3.1.2

View File

@@ -1,17 +0,0 @@
import { API_DOMAINS, http } from '@/http/alova'
export interface IFoo {
id: number
name: string
}
export function foo() {
return http.Get<IFoo>('/foo', {
params: {
name: '菲鸽',
page: 1,
pageSize: 10,
},
meta: { domain: API_DOMAINS.SECONDARY }, // 用于切换请求地址
})
}

View File

@@ -1,43 +0,0 @@
import { http } from '@/http/http'
export interface IFoo {
id: number
name: string
}
export function foo() {
return http.Get<IFoo>('/foo', {
params: {
name: '菲鸽',
page: 1,
pageSize: 10,
},
})
}
export interface IFooItem {
id: string
name: string
}
/** GET 请求 */
export async function getFooAPI(name: string) {
return await http.get<IFooItem>('/foo', { name })
}
/** GET 请求;支持 传递 header 的范例 */
export function getFooAPI2(name: string) {
return http.get<IFooItem>('/foo', { name }, { 'Content-Type-100': '100' })
}
/** POST 请求 */
export function postFooAPI(name: string) {
return http.post<IFooItem>('/foo', { name })
}
/** POST 请求;需要传递 query 参数的范例微信小程序经常有同时需要query参数和body参数的场景 */
export function postFooAPI2(name: string) {
return http.post<IFooItem>('/foo', { name }, { a: 1, b: 2 })
}
/** POST 请求;支持 传递 header 的范例 */
export function postFooAPI3(name: string) {
return http.post<IFooItem>('/foo', { name }, { a: 1, b: 2 }, { 'Content-Type-100': '100' })
}

View File

@@ -1,13 +0,0 @@
# 请求库
目前unibest支持3种请求库
- 菲鸽简单封装的 `简单版本http`路径src/http/http.ts对应的示例在 src/api/foo.ts
- `alova 的 http`路径src/http/alova.ts对应的示例在 src/api/foo-alova.ts
- `vue-query`, 路径src/http/vue-query.ts, 目前主要用在自动生成接口,详情看(https://unibest.tech/base/17-generate),示例在 src/service/app 文件夹
## 如何选择
如果您以前用过 alova 或者 vue-query可以优先使用您熟悉的。
如果您的项目简单简单版本的http 就够了也不会增加包体积。发版的时候可以去掉alova和vue-query如果没有超过包体积留着也无所谓 ^_^
## roadmap
菲鸽最近在优化脚手架后续可以选择是否使用第三方的请求库以及选择什么请求库。还在开发中大概月底出来8月31号

View File

@@ -1,119 +0,0 @@
import type { uniappRequestAdapter } from '@alova/adapter-uniapp'
import type { IResponse } from './types'
import AdapterUniapp from '@alova/adapter-uniapp'
import { createAlova } from 'alova'
import { createServerTokenAuthentication } from 'alova/client'
import VueHook from 'alova/vue'
import { toLoginPage } from '@/utils/toLoginPage'
import { ContentTypeEnum, ResultEnum, ShowMessage } from './tools/enum'
// 配置动态Tag
export const API_DOMAINS = {
DEFAULT: import.meta.env.VITE_SERVER_BASEURL,
SECONDARY: import.meta.env.VITE_SERVER_BASEURL_SECONDARY,
}
/**
* 创建请求实例
*/
const { onAuthRequired, onResponseRefreshToken } = createServerTokenAuthentication<
typeof VueHook,
typeof uniappRequestAdapter
>({
// 如果下面拦截不到,请使用 refreshTokenOnSuccess by 群友@琛
refreshTokenOnError: {
isExpired: (error) => {
return error.response?.status === ResultEnum.Unauthorized
},
handler: async () => {
try {
// await authLogin();
}
catch (error) {
// 切换到登录页
toLoginPage({ mode: 'reLaunch' })
throw error
}
},
},
})
/**
* alova 请求实例
*/
const alovaInstance = createAlova({
baseURL: API_DOMAINS.DEFAULT,
...AdapterUniapp(),
timeout: 5000,
statesHook: VueHook,
beforeRequest: onAuthRequired((method) => {
// 设置默认 Content-Type
method.config.headers = {
ContentType: ContentTypeEnum.JSON,
Accept: 'application/json, text/plain, */*',
...method.config.headers,
}
const { config } = method
const ignoreAuth = !config.meta?.ignoreAuth
console.log('ignoreAuth===>', ignoreAuth)
// 处理认证信息 自行处理认证问题
if (ignoreAuth) {
const token = 'getToken()'
if (!token) {
throw new Error('[请求错误]:未登录')
}
// method.config.headers.token = token;
}
// 处理动态域名
if (config.meta?.domain) {
method.baseURL = config.meta.domain
console.log('当前域名', method.baseURL)
}
}),
responded: onResponseRefreshToken((response, method) => {
const { config } = method
const { requestType } = config
const {
statusCode,
data: rawData,
errMsg,
} = response as UniNamespace.RequestSuccessCallbackResult
// 处理特殊请求类型(上传/下载)
if (requestType === 'upload' || requestType === 'download') {
return response
}
// 处理 HTTP 状态码错误
if (statusCode !== 200) {
const errorMessage = ShowMessage(statusCode) || `HTTP请求错误[${statusCode}]`
console.error('errorMessage===>', errorMessage)
uni.showToast({
title: errorMessage,
icon: 'error',
})
throw new Error(`${errorMessage}${errMsg}`)
}
// 处理业务逻辑错误
const { code, message, data } = rawData as IResponse
// 0和200当做成功都很普遍这里直接兼容两者见 ResultEnum
if (code !== ResultEnum.Success0 && code !== ResultEnum.Success200) {
if (config.meta?.toast !== false) {
uni.showToast({
title: message,
icon: 'none',
})
}
throw new Error(`请求错误[${code}]${message}`)
}
// 处理成功响应,返回业务数据
return data
}),
})
export const http = alovaInstance

View File

@@ -7,14 +7,6 @@ export type CustomRequestOptions = UniApp.RequestOptions & {
hideErrorToast?: boolean
} & IUniUploadFileOptions // 添加uni.uploadFile参数类型
/** 主要提供给 openapi-ts-request 生成的代码使用 */
export type CustomRequestOptions_ = Omit<CustomRequestOptions, 'url'>
export interface HttpRequestResult<T> {
promise: Promise<T>
requestTask: UniApp.RequestTask
}
// 通用响应格式(兼容 msg + message 字段)
export type IResponse<T = any> = {
code: number

View File

@@ -1,30 +0,0 @@
import type { CustomRequestOptions } from '@/http/types'
import { http } from './http'
/*
* openapi-ts-request 工具的 request 跨客户端适配方法
*/
export default function request<T extends { data?: any }>(
url: string,
options: Omit<CustomRequestOptions, 'url'> & {
params?: Record<string, unknown>
headers?: Record<string, unknown>
},
) {
const requestOptions = {
url,
...options,
}
if (options.params) {
requestOptions.query = requestOptions.params
delete requestOptions.params
}
if (options.headers) {
requestOptions.header = options.headers
delete requestOptions.headers
}
return http<T['data']>(requestOptions)
}

View File

@@ -1,6 +0,0 @@
/* eslint-disable */
// @ts-ignore
export * from './types';
export * from './listAll';
export * from './info';

View File

@@ -1,14 +0,0 @@
/* eslint-disable */
// @ts-ignore
import request from '@/http/vue-query';
import { CustomRequestOptions_ } from '@/http/types';
import * as API from './types';
/** 用户信息 GET /user/info */
export function infoUsingGet({ options }: { options?: CustomRequestOptions_ }) {
return request<API.InfoUsingGetResponse>('/user/info', {
method: 'GET',
...(options || {}),
});
}

View File

@@ -1,18 +0,0 @@
/* eslint-disable */
// @ts-ignore
import request from '@/http/vue-query';
import { CustomRequestOptions_ } from '@/http/types';
import * as API from './types';
/** 用户列表 GET /user/listAll */
export function listAllUsingGet({
options,
}: {
options?: CustomRequestOptions_;
}) {
return request<API.ListAllUsingGetResponse>('/user/listAll', {
method: 'GET',
...(options || {}),
});
}

View File

@@ -1,29 +0,0 @@
/* eslint-disable */
// @ts-ignore
export type InfoUsingGetResponse = {
code: number;
msg: string;
data: UserItem;
};
export type InfoUsingGetResponses = {
200: InfoUsingGetResponse;
};
export type ListAllUsingGetResponse = {
code: number;
msg: string;
data: UserItem[];
};
export type ListAllUsingGetResponses = {
200: ListAllUsingGetResponse;
};
export type UserItem = {
userId: number;
username: string;
nickname: string;
avatar: string;
};