feat(projects): 1.0 beta

This commit is contained in:
Soybean
2023-11-17 08:45:00 +08:00
parent 1ea4817f6a
commit e918a2c0f5
499 changed files with 15918 additions and 24708 deletions

View File

@ -1,27 +0,0 @@
import type { AxiosRequestConfig } from 'axios';
import { useAuthStore } from '@/store';
import { localStg } from '@/utils';
import { fetchUpdateToken } from '../api';
/**
* 刷新token
* @param axiosConfig - token失效时的请求配置
*/
export async function handleRefreshToken(axiosConfig: AxiosRequestConfig) {
const { resetAuthStore } = useAuthStore();
const refreshToken = localStg.get('refreshToken') || '';
const { data } = await fetchUpdateToken(refreshToken);
if (data) {
localStg.set('token', data.token);
localStg.set('refreshToken', data.refreshToken);
const config = { ...axiosConfig };
if (config.headers) {
config.headers.Authorization = data.token;
}
return config;
}
resetAuthStore();
return null;
}

View File

@ -1,10 +1,25 @@
import { getServiceEnvConfig } from '~/.env-config';
import { createRequest } from './request';
import { localStg } from '@/utils/storage';
import { createOfetch as createRequest } from '@sa/request';
import { createServiceConfig, createProxyPattern } from '~/env.config';
const { url, proxyPattern } = getServiceEnvConfig(import.meta.env);
const { baseURL, otherBaseURL } = createServiceConfig(import.meta.env);
const isHttpProxy = import.meta.env.VITE_HTTP_PROXY === 'Y';
export const request = createRequest({ baseURL: isHttpProxy ? proxyPattern : url });
export const request = createRequest({
baseURL: isHttpProxy ? createProxyPattern() : baseURL,
headers: {
apifoxToken: 'XL299LiMEDZ0H5h3A29PxwQXdMJqWyY2'
},
onRequest({ options }) {
if (options.headers) {
const token = localStg.get('token');
export const mockRequest = createRequest({ baseURL: '/mock' });
const Authorization = token ? `Bearer ${token}` : '';
Object.assign(options.headers, { Authorization });
}
}
});
export const demoRequest = createRequest({ baseURL: isHttpProxy ? createProxyPattern('demo') : otherBaseURL.demo });

View File

@ -1,114 +0,0 @@
import axios from 'axios';
import type { AxiosResponse, AxiosError, AxiosInstance, AxiosRequestConfig } from 'axios';
import { REFRESH_TOKEN_CODE } from '@/config';
import {
localStg,
handleAxiosError,
handleBackendError,
handleResponseError,
handleServiceResult,
transformRequestData
} from '@/utils';
import { handleRefreshToken } from './helpers';
type RefreshRequestQueue = (config: AxiosRequestConfig) => void;
/**
* 封装axios请求类
* @author Soybean<honghuangdc@gmail.com>
*/
export default class CustomAxiosInstance {
instance: AxiosInstance;
backendConfig: Service.BackendResultConfig;
isRefreshing: boolean;
retryQueues: RefreshRequestQueue[];
/**
*
* @param axiosConfig - axios配置
* @param backendConfig - 后端返回的数据配置
*/
constructor(
axiosConfig: AxiosRequestConfig,
backendConfig: Service.BackendResultConfig = {
codeKey: 'code',
dataKey: 'data',
msgKey: 'message',
successCode: 200
}
) {
this.backendConfig = backendConfig;
this.instance = axios.create(axiosConfig);
this.setInterceptor();
this.isRefreshing = false;
this.retryQueues = [];
}
/** 设置请求拦截器 */
setInterceptor() {
this.instance.interceptors.request.use(
async config => {
const handleConfig = { ...config };
if (handleConfig.headers) {
// 数据转换
const contentType = handleConfig.headers['Content-Type'] as UnionKey.ContentType;
handleConfig.data = await transformRequestData(handleConfig.data, contentType);
// 设置token
handleConfig.headers.Authorization = localStg.get('token') || '';
}
return handleConfig;
},
(axiosError: AxiosError) => {
const error = handleAxiosError(axiosError);
return handleServiceResult(error, null);
}
);
this.instance.interceptors.response.use(
(async response => {
const { status, config } = response;
if (status === 200 || status < 300 || status === 304) {
const backend = response.data;
const { codeKey, dataKey, successCode } = this.backendConfig;
// 请求成功
if (backend[codeKey] === successCode) {
return handleServiceResult(null, backend[dataKey]);
}
// token失效, 刷新token
if (REFRESH_TOKEN_CODE.includes(backend[codeKey])) {
// 原始请求
const originRequest = new Promise(resolve => {
this.retryQueues.push((refreshConfig: AxiosRequestConfig) => {
config.headers.Authorization = refreshConfig.headers?.Authorization;
resolve(this.instance.request(config));
});
});
if (!this.isRefreshing) {
this.isRefreshing = true;
const refreshConfig = await handleRefreshToken(response.config);
if (refreshConfig) {
this.retryQueues.map(cb => cb(refreshConfig));
}
this.retryQueues = [];
this.isRefreshing = false;
}
return originRequest;
}
const error = handleBackendError(backend, this.backendConfig);
return handleServiceResult(error, null);
}
const error = handleResponseError(response);
return handleServiceResult(error, null);
}) as (response: AxiosResponse<any, any>) => Promise<AxiosResponse<any, any>>,
(axiosError: AxiosError) => {
const error = handleAxiosError(axiosError);
return handleServiceResult(error, null);
}
);
}
}

View File

@ -1,208 +0,0 @@
import { ref } from 'vue';
import type { Ref } from 'vue';
import type { AxiosInstance, AxiosRequestConfig } from 'axios';
import { useBoolean, useLoading } from '@/hooks';
import CustomAxiosInstance from './instance';
type RequestMethod = 'get' | 'post' | 'put' | 'delete';
interface RequestParam {
url: string;
method?: RequestMethod;
data?: any;
axiosConfig?: AxiosRequestConfig;
}
/**
* 创建请求
* @param axiosConfig - axios配置
* @param backendConfig - 后端接口字段配置
*/
export function createRequest(axiosConfig: AxiosRequestConfig, backendConfig?: Service.BackendResultConfig) {
const customInstance = new CustomAxiosInstance(axiosConfig, backendConfig);
/**
* 异步promise请求
* @param param - 请求参数
* - url: 请求地址
* - method: 请求方法(默认get)
* - data: 请求的body的data
* - axiosConfig: axios配置
*/
async function asyncRequest<T>(param: RequestParam): Promise<Service.RequestResult<T>> {
const { url } = param;
const method = param.method || 'get';
const { instance } = customInstance;
const res = (await getRequestResponse({
instance,
method,
url,
data: param.data,
config: param.axiosConfig
})) as Service.RequestResult<T>;
return res;
}
/**
* get请求
* @param url - 请求地址
* @param config - axios配置
*/
function get<T>(url: string, config?: AxiosRequestConfig) {
return asyncRequest<T>({ url, method: 'get', axiosConfig: config });
}
/**
* post请求
* @param url - 请求地址
* @param data - 请求的body的data
* @param config - axios配置
*/
function post<T>(url: string, data?: any, config?: AxiosRequestConfig) {
return asyncRequest<T>({ url, method: 'post', data, axiosConfig: config });
}
/**
* put请求
* @param url - 请求地址
* @param data - 请求的body的data
* @param config - axios配置
*/
function put<T>(url: string, data?: any, config?: AxiosRequestConfig) {
return asyncRequest<T>({ url, method: 'put', data, axiosConfig: config });
}
/**
* delete请求
* @param url - 请求地址
* @param config - axios配置
*/
function handleDelete<T>(url: string, config?: AxiosRequestConfig) {
return asyncRequest<T>({ url, method: 'delete', axiosConfig: config });
}
return {
get,
post,
put,
delete: handleDelete
};
}
interface RequestResultHook<T = any> {
data: Ref<T | null>;
error: Ref<Service.RequestError | null>;
loading: Ref<boolean>;
network: Ref<boolean>;
}
/**
* 创建hooks请求
* @param axiosConfig - axios配置
* @param backendConfig - 后端接口字段配置
*/
export function createHookRequest(axiosConfig: AxiosRequestConfig, backendConfig?: Service.BackendResultConfig) {
const customInstance = new CustomAxiosInstance(axiosConfig, backendConfig);
/**
* hooks请求
* @param param - 请求参数
* - url: 请求地址
* - method: 请求方法(默认get)
* - data: 请求的body的data
* - axiosConfig: axios配置
*/
function useRequest<T>(param: RequestParam): RequestResultHook<T> {
const { loading, startLoading, endLoading } = useLoading();
const { bool: network, setBool: setNetwork } = useBoolean(window.navigator.onLine);
startLoading();
const data = ref<T | null>(null) as Ref<T | null>;
const error = ref<Service.RequestError | null>(null);
function handleRequestResult(response: any) {
const res = response as Service.RequestResult<T>;
data.value = res.data;
error.value = res.error;
endLoading();
setNetwork(window.navigator.onLine);
}
const { url } = param;
const method = param.method || 'get';
const { instance } = customInstance;
getRequestResponse({ instance, method, url, data: param.data, config: param.axiosConfig }).then(
handleRequestResult
);
return {
data,
error,
loading,
network
};
}
/**
* get请求
* @param url - 请求地址
* @param config - axios配置
*/
function get<T>(url: string, config?: AxiosRequestConfig) {
return useRequest<T>({ url, method: 'get', axiosConfig: config });
}
/**
* post请求
* @param url - 请求地址
* @param data - 请求的body的data
* @param config - axios配置
*/
function post<T>(url: string, data?: any, config?: AxiosRequestConfig) {
return useRequest<T>({ url, method: 'post', data, axiosConfig: config });
}
/**
* put请求
* @param url - 请求地址
* @param data - 请求的body的data
* @param config - axios配置
*/
function put<T>(url: string, data?: any, config?: AxiosRequestConfig) {
return useRequest<T>({ url, method: 'put', data, axiosConfig: config });
}
/**
* delete请求
* @param url - 请求地址
* @param config - axios配置
*/
function handleDelete<T>(url: string, config: AxiosRequestConfig) {
return useRequest<T>({ url, method: 'delete', axiosConfig: config });
}
return {
get,
post,
put,
delete: handleDelete
};
}
async function getRequestResponse(params: {
instance: AxiosInstance;
method: RequestMethod;
url: string;
data?: any;
config?: AxiosRequestConfig;
}) {
const { instance, method, url, data, config } = params;
let res: any;
if (method === 'get' || method === 'delete') {
res = await instance[method](url, config);
} else {
res = await instance[method](url, data, config);
}
return res;
}