Files
ndm-web-platform/src/pages/vimp/apis/client/vimp-client.ts
T
yangsy 6fed499d78 feat(vimp客户端): 补充完整请求方法并添加统一认证与错误处理
- 新增VimpRequestOptions配置接口,支持自定义请求、响应及错误拦截器
- 补充get、put、delete请求方法并封装统一响应格式
- 添加默认请求拦截器自动携带公共认证参数
- 实现401错误拦截,超时自动跳转登录页并重置用户状态
2026-06-04 22:06:49 +08:00

153 lines
5.5 KiB
TypeScript

import type { AxiosError, AxiosRequestConfig, AxiosResponse, CreateAxiosDefaults, InternalAxiosRequestConfig } from 'axios';
import axios, { isAxiosError } from 'axios';
import type { VimpResponse, VimpResult } from '../../types';
import { useUserStore } from '@/stores';
import { getAppEnvConfig } from '@/utils';
import router from '@/router';
export interface VimpRequestOptions extends CreateAxiosDefaults {
requestInterceptor?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>;
responseInterceptor?: (resp: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>;
responseErrorInterceptor?: (error: any) => any;
}
export const createVimpClient = (config?: VimpRequestOptions) => {
const defaultRequestInterceptor = (config: InternalAxiosRequestConfig) => config;
const defaultResponseInterceptor = (response: AxiosResponse) => response;
const defaultResponseErrorInterceptor = (error: any) => {
if (isAxiosError(error)) {
if (error.status === 401) {
// 处理 401 错误
}
if (error.status === 404) {
// 处理 404 错误
}
}
return Promise.reject(error);
};
const requestInterceptor = config?.requestInterceptor ?? defaultRequestInterceptor;
const responseInterceptor = config?.responseInterceptor ?? defaultResponseInterceptor;
const responseErrorInterceptor = config?.responseErrorInterceptor ?? defaultResponseErrorInterceptor;
const instance = axios.create(config);
instance.interceptors.request.use(requestInterceptor);
instance.interceptors.response.use(responseInterceptor, responseErrorInterceptor);
const vimpGet = <T>(url: string, options?: AxiosRequestConfig & { retRaw?: boolean }): Promise<VimpResponse<T>> => {
const { retRaw, ...reqConfig } = options ?? {};
return new Promise((resolve) => {
instance
.get(url, {
...reqConfig,
})
.then((res) => {
if (retRaw) {
resolve([null, res.data as T, null]);
} else {
const resData = res.data as VimpResult<T>;
resolve([null, resData.data, resData]);
}
})
.catch((err) => {
resolve([err as AxiosError, null, null]);
});
});
};
const vimpPost = <T>(url: string, data?: AxiosRequestConfig['data'], options?: Partial<Omit<AxiosRequestConfig, 'data'>> & { retRaw?: boolean; upload?: boolean }): Promise<VimpResponse<T>> => {
const { retRaw, upload, ...reqConfig } = options ?? {};
return new Promise((resolve) => {
instance
.post(url, data, { headers: { 'content-type': upload ? 'multipart/form-data' : 'application/json' }, ...reqConfig })
.then((res) => {
const resData = res.data;
if (retRaw) {
resolve([null, resData as T, null]);
} else {
resolve([null, resData.data as T, resData as VimpResult<T>]);
}
})
.catch((err) => {
resolve([err as AxiosError, null, null]);
});
});
};
const httpPut = <T>(url: string, data?: AxiosRequestConfig['data'], options?: Partial<Omit<AxiosRequestConfig, 'data'>>): Promise<VimpResponse<T>> => {
const reqConfig = options ?? {};
return new Promise((resolve) => {
instance
.put<VimpResult<T>>(url, data, { ...reqConfig })
.then((res) => {
resolve([null, res.data.data, res.data]);
})
.catch((err) => {
resolve([err as AxiosError, null, null]);
});
});
};
const httpDelete = <T>(url: string, idList: string[], options?: Partial<Omit<AxiosRequestConfig, 'data'>>): Promise<VimpResponse<T>> => {
const reqConfig = options ?? {};
return new Promise((resolve) => {
instance
.delete<VimpResult<T>>(url, { ...reqConfig, data: idList })
.then((res) => {
resolve([null, res.data.data, res.data]);
})
.catch((err) => {
resolve([err as AxiosError, null, null]);
});
});
};
return {
instance,
get: vimpGet,
post: vimpPost,
put: httpPut,
delete: httpDelete,
};
};
export const unwrapVimpResponse = <T>(resp: VimpResponse<T>) => {
const [err, data, result] = resp;
if (err) throw err;
if (result) {
const { code, msg } = result;
if (code !== 0 && code !== 200) throw new Error(`${msg || '请求失败'}`);
}
return data;
};
export const vimpClient = createVimpClient({
baseURL: `/vimp/api/client`,
requestInterceptor: (config) => {
const userStore = useUserStore();
const { lampAuthorization, lampClientId, lampClientSecret } = getAppEnvConfig();
const newAuthorization = window.btoa(`${lampClientId}:${lampClientSecret}`);
const authorization = lampAuthorization.trim() !== '' ? lampAuthorization : newAuthorization;
config.headers.set('accept-language', 'zh-CN,zh;q=0.9');
config.headers.set('accept', 'application/json, text/plain, */*');
config.headers.set('Applicationid', '');
config.headers.set('Tenantid', '1');
config.headers.set('Authorization', authorization);
config.headers.set('token', userStore.userLoginResult?.token ?? '');
return config;
},
responseInterceptor: (response) => {
return response;
},
responseErrorInterceptor: (error) => {
const err = error as AxiosError;
if (err.response?.status === 401) {
window.$message.error('登录超时,请重新登录');
const userStore = useUserStore();
userStore.resetStore();
router.push({ path: '/login' });
}
return Promise.reject(error);
},
});