refactor(projects): 文件夹位置规范

This commit is contained in:
Soybean
2021-11-23 10:52:30 +08:00
parent 3fb7a5f709
commit f5a5f44a2b
26 changed files with 60 additions and 192 deletions

View File

@ -1,8 +0,0 @@
import type { AxiosRequestConfig } from 'axios';
import CustomAxiosInstance from './instance';
import Request from './request';
export function createRequest(axiosConfig: AxiosRequestConfig) {
const customInstance = new CustomAxiosInstance(axiosConfig);
return new Request(customInstance.instance);
}

View File

@ -1,39 +0,0 @@
/** 请求超时时间 */
export const REQUEST_TIMEOUT = 60 * 1000;
/** 错误信息的显示时间 */
export const ERROR_MSG_DURATION = 3 * 1000;
/** 兜底的请求错误code */
export const DEFAULT_REQUEST_ERROR_CODE = 'DEFAULT';
/** 兜底的请求错误文本 */
export const DEFAULT_REQUEST_ERROR_MSG = '请求错误~';
/** 请求超时的错误code(为固定值ECONNABORTED) */
export const REQUEST_TIMEOUT_CODE = 'ECONNABORTED';
/** 请求超时的错误文本 */
export const REQUEST_TIMEOUT_MSG = '请求超时~';
/** 网络不可用的code */
export const NETWORK_ERROR_CODE = 'NETWORK_ERROR';
/** 网络不可用的错误文本 */
export const NETWORK_ERROR_MSG = '网络不可用~';
/** 请求不成功各种状态的错误 */
export const ERROR_STATUS = {
400: '400: 请求出现语法错误',
401: '401: 用户未授权~',
403: '403: 服务器拒绝访问~',
404: '404: 请求的资源不存在~',
405: '405: 请求方法未允许~',
408: '408: 网络请求超时~',
500: '500: 服务器内部错误~',
501: '501: 服务器未实现请求功能~',
502: '502: 错误网关~',
503: '503: 服务不可用~',
504: '504: 网关超时~',
505: '505: http版本不支持该请求~'
};
/** 不弹出错误信息的code */
export const NO_ERROR_MSG_CODE: (string | number)[] = [];

View File

@ -1,85 +0,0 @@
import type { AxiosError, AxiosResponse } from 'axios';
import type { RequestServiceError, BackendServiceResult } from '@/interface';
import {
DEFAULT_REQUEST_ERROR_CODE,
DEFAULT_REQUEST_ERROR_MSG,
NETWORK_ERROR_CODE,
NETWORK_ERROR_MSG,
REQUEST_TIMEOUT_CODE,
REQUEST_TIMEOUT_MSG,
ERROR_STATUS
} from '../config';
import { showErrorMsg } from './msg';
type ErrorStatus = keyof typeof ERROR_STATUS;
/**
* 处理请求失败的错误
* @param error - 错误
*/
export function handleAxiosError(axiosError: AxiosError) {
const error: RequestServiceError = {
type: 'axios',
code: DEFAULT_REQUEST_ERROR_CODE,
msg: DEFAULT_REQUEST_ERROR_MSG
};
if (!window.navigator.onLine || axiosError.message === 'Network Error') {
// 网路错误
Object.assign(error, { code: NETWORK_ERROR_CODE, msg: NETWORK_ERROR_MSG });
} else if (axiosError.code === REQUEST_TIMEOUT_CODE && axiosError.message.includes('timeout')) {
/** 超时错误 */
Object.assign(error, { code: REQUEST_TIMEOUT_CODE, msg: REQUEST_TIMEOUT_MSG });
} else if (axiosError.response) {
// 请求不成功的错误
const errorCode: ErrorStatus = axiosError.response.status as ErrorStatus;
const msg = ERROR_STATUS[errorCode] || DEFAULT_REQUEST_ERROR_MSG;
Object.assign(error, { code: errorCode || DEFAULT_REQUEST_ERROR_CODE, msg });
}
showErrorMsg(error);
return error;
}
/**
* 处理请求成功后的错误
* @param response - 请求的响应
*/
export function handleResponseError(response: AxiosResponse) {
const error: RequestServiceError = {
type: 'axios',
code: DEFAULT_REQUEST_ERROR_CODE,
msg: DEFAULT_REQUEST_ERROR_MSG
};
if (!window.navigator.onLine) {
// 网路错误
Object.assign(error, { code: NETWORK_ERROR_CODE, msg: NETWORK_ERROR_MSG });
} else {
// 请求成功的状态码非200的错误
const errorCode: ErrorStatus = response.status as ErrorStatus;
const msg = ERROR_STATUS[errorCode] || DEFAULT_REQUEST_ERROR_MSG;
Object.assign(error, { type: 'backend', code: errorCode, msg });
}
showErrorMsg(error);
return error;
}
/**
* 处理后端返回的错误
* @param backendResult - 后端接口的响应数据
*/
export function handleBackendError(backendResult: BackendServiceResult) {
const error: RequestServiceError = {
type: 'backend',
code: backendResult.code,
msg: backendResult.message
};
showErrorMsg(error);
return error;
}

View File

@ -1,24 +0,0 @@
import { CustomRequestResult, CustomSuccessRequestResult, CustomFailRequestResult } from '@/interface';
type ResultHandler<T> = (...arg: any) => T;
/**
* 对请求的结果数据进行格式化的处理
* @param resultHandler - 处理函数
* @param requests - 请求结果
*/
export function resultMiddleware<MiddlewareData>(
resultHandler: ResultHandler<MiddlewareData>,
requests: CustomRequestResult<any>[]
) {
const errorIndex = requests.findIndex(item => item.error !== null);
const hasError = errorIndex > -1;
const successResult: CustomSuccessRequestResult<MiddlewareData> = {
data: resultHandler(...requests.map(item => item.data)),
error: null
};
const failResult: CustomFailRequestResult = {
data: null,
error: requests[errorIndex].error!
};
return hasError ? failResult : successResult;
}

View File

@ -1,3 +0,0 @@
export * from './transform';
export * from './error';
export * from './handler';

View File

@ -1,31 +0,0 @@
import type { RequestServiceError } from '@/interface';
import { NO_ERROR_MSG_CODE, ERROR_MSG_DURATION } from '../config';
/** 错误消息栈,防止同一错误同时出现 */
const errorMsgStack = new Map<string | number, string>([]);
function addErrorMsg(error: RequestServiceError) {
errorMsgStack.set(error.code, error.msg);
}
function removeErrorMsg(error: RequestServiceError) {
errorMsgStack.delete(error.code);
}
function hasErrorMsg(error: RequestServiceError) {
return errorMsgStack.has(error.code);
}
/**
* 显示错误信息
* @param error
*/
export function showErrorMsg(error: RequestServiceError) {
if (!NO_ERROR_MSG_CODE.includes(error.code)) {
if (!hasErrorMsg(error)) {
addErrorMsg(error);
window.$message?.error(error.msg, { duration: ERROR_MSG_DURATION });
setTimeout(() => {
removeErrorMsg(error);
}, ERROR_MSG_DURATION);
}
}
}

View File

@ -1,47 +0,0 @@
import qs from 'qs';
import FormData from 'form-data';
import { isArray } from '@/utils';
import { ContentType } from '@/enum';
/**
* 请求数据的转换
* @param requestData - 请求数据
* @param contentType - 请求头的Content-Type
*/
export async function transformRequestData(requestData: any, contentType?: string) {
// application/json类型不处理
let data = requestData;
// form类型转换
if (contentType === ContentType.formUrlencoded) {
data = qs.stringify(requestData);
}
// form-data类型转换
if (contentType === ContentType.formData) {
const key = Object.keys(requestData)[0];
const file = requestData.data[key];
data = await transformFile(file, key);
}
return data;
}
/**
* 接口为上传文件的类型时数据转换
* @param file - 单文件或多文件
* @param key - 文件的属性名
*/
async function transformFile(file: File[] | File, key: string) {
const formData = new FormData();
if (isArray(file)) {
// 多文件
await Promise.all(
(file as File[]).map(item => {
formData.append(key, item);
return true;
})
);
} else {
// 单文件
await formData.append(key, file);
}
return formData;
}

View File

@ -1,9 +1,7 @@
import { createRequest } from './axios';
import { REQUEST_TIMEOUT } from './config';
import { REQUEST_TIMEOUT } from '@/config';
import { createRequest } from './request';
export const request = createRequest({
baseURL: import.meta.env.VITE_HTTP_URL,
timeout: REQUEST_TIMEOUT
});
export { resultMiddleware } from './helpers';

View File

@ -1,8 +1,7 @@
import axios from 'axios';
import type { AxiosRequestConfig, AxiosInstance, AxiosError, CancelTokenStatic } from 'axios';
import { getToken } from '@/utils';
import { getToken, transformRequestData, handleAxiosError, handleResponseError, handleBackendError } from '@/utils';
import type { BackendServiceResult } from '@/interface';
import { transformRequestData, handleAxiosError, handleResponseError, handleBackendError } from '../helpers';
/**
* axios请求类

View File

@ -1,11 +1,12 @@
import type { AxiosRequestConfig, AxiosInstance, AxiosResponse } from 'axios';
import type { RequestServiceError, CustomSuccessRequestResult, CustomFailRequestResult } from '@/interface';
import CustomAxiosInstance from './instance';
/**
*
* @author Soybean<honghuangdc@gmail.com>
*/
export default class Request {
export class Request {
instance: AxiosInstance;
constructor(instance: AxiosInstance) {
@ -58,3 +59,8 @@ export default class Request {
.catch(Request.failHandler);
}
}
export function createRequest(axiosConfig: AxiosRequestConfig) {
const customInstance = new CustomAxiosInstance(axiosConfig);
return new Request(customInstance.instance);
}