可用版本
This commit is contained in:
parent
445766b458
commit
a7bc39c70f
@ -50,19 +50,19 @@ const BasicLayout: React.FC = () => {
|
|||||||
// 初始化用户数据
|
// 初始化用户数据
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const initializeUserData = async () => {
|
const initializeUserData = async () => {
|
||||||
try {
|
// try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const userData = await getCurrentUser();
|
const menuData = await getCurrentUserMenus()
|
||||||
dispatch(setUserInfo(userData));
|
|
||||||
const menuData = await getCurrentUserMenus();
|
|
||||||
dispatch(setMenus(menuData));
|
dispatch(setMenus(menuData));
|
||||||
} catch (error) {
|
|
||||||
message.error('初始化用户数据失败');
|
|
||||||
dispatch(logout());
|
|
||||||
navigate('/login', {replace: true});
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
// } catch (error) {
|
||||||
|
// console.log(error);
|
||||||
|
// message.error('初始化用户数据失败');
|
||||||
|
// dispatch(logout());
|
||||||
|
// navigate('/login', {replace: true});
|
||||||
|
// } finally {
|
||||||
|
// setLoading(false);
|
||||||
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!userInfo) {
|
if (!userInfo) {
|
||||||
@ -137,7 +137,7 @@ const BasicLayout: React.FC = () => {
|
|||||||
|
|
||||||
// 将菜单数据转换为antd Menu需要的格式
|
// 将菜单数据转换为antd Menu需要的格式
|
||||||
const getMenuItems = (menuList: MenuResponse[]): MenuProps['items'] => {
|
const getMenuItems = (menuList: MenuResponse[]): MenuProps['items'] => {
|
||||||
return menuList.map(menu => ({
|
return menuList?.map(menu => ({
|
||||||
key: menu.path || menu.id.toString(),
|
key: menu.path || menu.id.toString(),
|
||||||
icon: getIcon(menu.icon),
|
icon: getIcon(menu.icon),
|
||||||
label: menu.name,
|
label: menu.name,
|
||||||
|
|||||||
@ -16,9 +16,7 @@ export const logout = async (): Promise<void> => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getCurrentUser = async (): Promise<LoginResponse> => {
|
export const getCurrentUser = async (): Promise<LoginResponse> => {
|
||||||
return request.get('/api/v1/user/current', {
|
return request.get('/api/v1/user/current');
|
||||||
errorMessage: '获取用户信息失败,请重新登录'
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getUserMenus = async (): Promise<MenuResponse[]> => {
|
export const getUserMenus = async (): Promise<MenuResponse[]> => {
|
||||||
|
|||||||
@ -33,7 +33,5 @@ export const getMenuTree = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getCurrentUserMenus = async (): Promise<MenuResponse[]> => {
|
export const getCurrentUserMenus = async (): Promise<MenuResponse[]> => {
|
||||||
return request.get('/api/v1/menu/current', {
|
return request.get('/api/v1/menu/current');
|
||||||
errorMessage: '获取菜单失败,请刷新页面重试'
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
@ -6,6 +6,7 @@ import type {DepartmentDTO} from '../Department/types';
|
|||||||
import {getUsers, createUser, updateUser, deleteUser, resetPassword} from './service';
|
import {getUsers, createUser, updateUser, deleteUser, resetPassword} from './service';
|
||||||
import {useTableData} from '@/hooks/useTableData';
|
import {useTableData} from '@/hooks/useTableData';
|
||||||
import type {FixedType, AlignType} from 'rc-table/lib/interface';
|
import type {FixedType, AlignType} from 'rc-table/lib/interface';
|
||||||
|
import {Response} from "@/utils/request.ts";
|
||||||
|
|
||||||
const UserPage: React.FC = () => {
|
const UserPage: React.FC = () => {
|
||||||
const {
|
const {
|
||||||
@ -80,23 +81,30 @@ const UserPage: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
try {
|
const values = await form.validateFields()
|
||||||
const values = await form.validateFields();
|
.catch(() => {
|
||||||
if (editingUser) {
|
// 表单验证失败,直接返回
|
||||||
await updateUser(editingUser.id, {
|
return Promise.reject();
|
||||||
|
});
|
||||||
|
|
||||||
|
const request = editingUser
|
||||||
|
? updateUser(editingUser.id, {
|
||||||
...values,
|
...values,
|
||||||
version: editingUser.version
|
version: editingUser.version
|
||||||
});
|
})
|
||||||
message.success('更新成功');
|
: createUser(values);
|
||||||
} else {
|
|
||||||
await createUser(values);
|
return request
|
||||||
message.success('创建成功');
|
.then(res => {
|
||||||
}
|
message.success(editingUser ? '更新用户成功' : '新增用户成功');
|
||||||
setModalVisible(false);
|
setModalVisible(false);
|
||||||
fetchUsers();
|
fetchUsers();
|
||||||
} catch (error) {
|
})
|
||||||
message.error('操作失败');
|
.catch(error => {
|
||||||
|
if (error.code) {
|
||||||
|
message.error(error.message);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTreeData = (deps: DepartmentDTO[]): any[] => {
|
const getTreeData = (deps: DepartmentDTO[]): any[] => {
|
||||||
|
|||||||
@ -6,61 +6,38 @@ import type { Page } from '@/types/base/page';
|
|||||||
export const getUsers = async (params?: UserQuery) => {
|
export const getUsers = async (params?: UserQuery) => {
|
||||||
return request.get<Page<UserResponse>>('/api/v1/user/page', {
|
return request.get<Page<UserResponse>>('/api/v1/user/page', {
|
||||||
params,
|
params,
|
||||||
errorMessage: '获取用户列表失败,请刷新重试'
|
retryCount: 3,
|
||||||
|
retryDelay: 1000,
|
||||||
|
cancelPrevious: true,
|
||||||
|
transform: true,
|
||||||
|
customMessage: '获取用户列表失败',
|
||||||
|
beforeRequest: () => {
|
||||||
|
console.log('开始请求');
|
||||||
|
},
|
||||||
|
afterResponse: () => {
|
||||||
|
console.log('请求完成');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getUserList = async (params?: UserQuery) => {
|
export const getUserList = async (params?: UserQuery) => {
|
||||||
return request.get<BaseResponse<UserResponse[]>>('/api/v1/user/list', {
|
return request.get<BaseResponse<UserResponse[]>>('/api/v1/user/list', {
|
||||||
params,
|
params
|
||||||
errorMessage: '获取用户列表失败,请刷新重试'
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createUser = async (data: UserRequest) => {
|
export const createUser = async (data: UserRequest): Promise<Response> => {
|
||||||
return request.post('/api/v1/user', data, {
|
return request.post('/api/v1/user', data, { hideMessage: true });
|
||||||
errorMessage: '创建用户失败,请稍后重试'
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateUser = async (id: number, data: UserRequest) => {
|
export const updateUser = async (id: number, data: UserRequest) => {
|
||||||
return request.put(`/api/v1/user/${id}`, data, {
|
return request.put(`/api/v1/user/${id}`, data);
|
||||||
errorMessage: '更新用户信息失败,请稍后重试'
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteUser = async (id: number) => {
|
export const deleteUser = async (id: number) => {
|
||||||
return request.delete<void>(`/api/v1/user/${id}`, {
|
return request.delete<void>(`/api/v1/user/${id}`, {});
|
||||||
errorMessage: '删除用户失败'
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const assignRoles = async (userId: number, roleIds: number[]) => {
|
export const resetPassword = async (id: number, password: string) => {
|
||||||
return request.post(`/api/v1/user/${userId}/roles`, roleIds, {
|
return request.post(`/api/v1/user/${id}/reset-password`, password);
|
||||||
errorMessage: '分配角色失败,请稍后重试'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const resetPassword = async (id: number) => {
|
|
||||||
return request.post(`/api/v1/user/${id}/reset-password`, null, {
|
|
||||||
errorMessage: '重置密码失败,请稍后重试'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updatePassword = async (id: number, data: { oldPassword: string; newPassword: string }) => {
|
|
||||||
return request.post(`/api/v1/user/${id}/update-password`, data, {
|
|
||||||
errorMessage: '修改密码失败,请稍后重试'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const enableUser = async (id: number) => {
|
|
||||||
return request.post(`/api/v1/user/${id}/enable`, null, {
|
|
||||||
errorMessage: '启用用户失败,请稍后重试'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const disableUser = async (id: number) => {
|
|
||||||
return request.post(`/api/v1/user/${id}/disable`, null, {
|
|
||||||
errorMessage: '禁用用户失败,请稍后重试'
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
16
frontend/src/types/error.ts
Normal file
16
frontend/src/types/error.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export interface ApiError {
|
||||||
|
code: number;
|
||||||
|
message: string;
|
||||||
|
details?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BusinessError extends Error {
|
||||||
|
constructor(
|
||||||
|
public code: number,
|
||||||
|
message: string,
|
||||||
|
public details?: any
|
||||||
|
) {
|
||||||
|
super(message);
|
||||||
|
this.name = 'BusinessError';
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import axios, {AxiosRequestConfig, AxiosResponse} from 'axios';
|
import axios, {AxiosRequestConfig, AxiosResponse} from 'axios';
|
||||||
import {message} from 'antd';
|
import {message} from 'antd';
|
||||||
|
|
||||||
export interface ApiResponse<T = any> {
|
export interface Response<T = any> {
|
||||||
code: number;
|
code: number;
|
||||||
message: string;
|
message: string;
|
||||||
data: T;
|
data: T;
|
||||||
@ -9,85 +9,305 @@ export interface ApiResponse<T = any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface RequestOptions extends AxiosRequestConfig {
|
export interface RequestOptions extends AxiosRequestConfig {
|
||||||
skipErrorHandler?: boolean;
|
hideMessage?: boolean;
|
||||||
hideErrorMessage?: boolean;
|
customMessage?: string;
|
||||||
errorMessage?: string;
|
transform?: boolean;
|
||||||
|
retryCount?: number;
|
||||||
|
retryDelay?: number;
|
||||||
|
retryAttempt?: number;
|
||||||
|
cancelPrevious?: boolean;
|
||||||
|
skipQueue?: boolean;
|
||||||
|
onUploadProgress?: (progressEvent: any) => void;
|
||||||
|
onDownloadProgress?: (progressEvent: any) => void;
|
||||||
|
beforeRequest?: (config: AxiosRequestConfig) => void | Promise<void>;
|
||||||
|
afterResponse?: (response: any) => void | Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const request = axios.create({
|
const request = axios.create({
|
||||||
baseURL: '',
|
baseURL: '',
|
||||||
timeout: 300000,
|
timeout: 30000,
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
request.interceptors.request.use(
|
const responseHandler = (response: AxiosResponse<Response<any>>) => {
|
||||||
(config) => {
|
|
||||||
const token = localStorage.getItem('token');
|
|
||||||
const tenantId = localStorage.getItem('tenantId');
|
|
||||||
|
|
||||||
if (token) {
|
|
||||||
config.headers.Authorization = `Bearer ${token}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tenantId) {
|
|
||||||
config.headers['X-Tenant-Id'] = tenantId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
request.interceptors.response.use(
|
|
||||||
(response: AxiosResponse<ApiResponse<any>>) => {
|
|
||||||
const res = response.data;
|
const res = response.data;
|
||||||
const config = response.config as RequestOptions;
|
const config = response.config as RequestOptions;
|
||||||
|
|
||||||
if (res.success) {
|
if (res.success && res.code === 200) {
|
||||||
return res.data;
|
!config.hideMessage && message.success(config.customMessage || res.message);
|
||||||
}
|
return config.transform ? res.data : res;
|
||||||
|
|
||||||
if (!config.hideErrorMessage) {
|
|
||||||
message.error(res.message || '操作失败');
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.reject(new Error(res.message));
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
const config = error.config as RequestOptions;
|
|
||||||
const response = error.response;
|
|
||||||
|
|
||||||
if (!config.hideErrorMessage) {
|
|
||||||
if (response?.data?.message && response?.status !== 500) {
|
|
||||||
message.error(response.data.message);
|
|
||||||
} else {
|
} else {
|
||||||
message.error(config.errorMessage || '系统错误,请稍后重试');
|
!config.hideMessage && message.error(config.customMessage || res.message);
|
||||||
|
return Promise.reject(res);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const extendedRequest = {
|
|
||||||
get: <T = any>(url: string, config?: RequestOptions) =>
|
|
||||||
request.get<any, T>(url, config),
|
|
||||||
|
|
||||||
post: <T = any>(url: string, data?: any, config?: RequestOptions) =>
|
|
||||||
request.post<any, T>(url, data, config),
|
|
||||||
|
|
||||||
put: <T = any>(url: string, data?: any, config?: RequestOptions) =>
|
|
||||||
request.put<any, T>(url, data, config),
|
|
||||||
|
|
||||||
delete: <T = any>(url: string, config?: RequestOptions) =>
|
|
||||||
request.delete<any, T>(url, config),
|
|
||||||
|
|
||||||
request: request
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default extendedRequest;
|
const errorHandler = (error: any) => {
|
||||||
|
const config = error.config as RequestOptions;
|
||||||
|
|
||||||
|
if (!error.response) {
|
||||||
|
message.error('网络连接异常,请检查网络');
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (axios.isCancel(error)) {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const status = error.response.status;
|
||||||
|
let msg = '';
|
||||||
|
switch (status) {
|
||||||
|
case 401:
|
||||||
|
msg = '未授权,请重新登录';
|
||||||
|
break;
|
||||||
|
case 403:
|
||||||
|
msg = '拒绝访问';
|
||||||
|
break;
|
||||||
|
case 404:
|
||||||
|
msg = '请求错误,未找到该资源';
|
||||||
|
break;
|
||||||
|
case 500:
|
||||||
|
msg = '服务器错误';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
msg = '服务器异常,请稍后再试!';
|
||||||
|
}
|
||||||
|
|
||||||
|
!config.hideMessage && message.error(config.customMessage || msg);
|
||||||
|
return Promise.reject(error);
|
||||||
|
};
|
||||||
|
|
||||||
|
request.interceptors.request.use(
|
||||||
|
(config) => {
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
|
if (token) {
|
||||||
|
config.headers.Authorization = `Bearer ${token}`;
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
(error) => Promise.reject(error)
|
||||||
|
);
|
||||||
|
|
||||||
|
request.interceptors.response.use(responseHandler, errorHandler);
|
||||||
|
|
||||||
|
const http = {
|
||||||
|
get: <T = any>(url: string, config?: RequestOptions) =>
|
||||||
|
request.get<any, Response<T>>(url, { transform: true, ...config }),
|
||||||
|
|
||||||
|
post: <T = any>(url: string, data?: any, config?: RequestOptions) =>
|
||||||
|
request.post<any, Response<T>>(url, data, { transform: true, ...config }),
|
||||||
|
|
||||||
|
put: <T = any>(url: string, data?: any, config?: RequestOptions) =>
|
||||||
|
request.put<any, Response<T>>(url, data, { transform: true, ...config }),
|
||||||
|
|
||||||
|
delete: <T = any>(url: string, config?: RequestOptions) =>
|
||||||
|
request.delete<any, Response<T>>(url, { transform: true, ...config }),
|
||||||
|
|
||||||
|
upload: <T = any>(url: string, file: File, config?: RequestOptions) => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
return request.post<any, Response<T>>(url, formData, {
|
||||||
|
headers: { 'Content-Type': 'multipart/form-data' },
|
||||||
|
...config
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
download: (url: string, filename?: string, config?: RequestOptions) =>
|
||||||
|
request.get(url, {
|
||||||
|
responseType: 'blob',
|
||||||
|
...config
|
||||||
|
}).then(response => {
|
||||||
|
const blob = new Blob([response.data]);
|
||||||
|
const downloadUrl = window.URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = downloadUrl;
|
||||||
|
link.download = filename || '';
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
window.URL.revokeObjectURL(downloadUrl);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
export class RequestCancel {
|
||||||
|
private static pendingMap = new Map<string, AbortController>();
|
||||||
|
|
||||||
|
static add(config: AxiosRequestConfig) {
|
||||||
|
const url = [config.method, config.url].join('&');
|
||||||
|
this.remove(url);
|
||||||
|
const controller = new AbortController();
|
||||||
|
config.signal = controller.signal;
|
||||||
|
this.pendingMap.set(url, controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
static remove(url: string) {
|
||||||
|
const controller = this.pendingMap.get(url);
|
||||||
|
controller?.abort();
|
||||||
|
this.pendingMap.delete(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
static removeAll() {
|
||||||
|
this.pendingMap.forEach(controller => controller.abort());
|
||||||
|
this.pendingMap.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const retryRequest = async (error: any) => {
|
||||||
|
const config = error.config as RequestOptions;
|
||||||
|
if (!config || !config.retryCount) return Promise.reject(error);
|
||||||
|
|
||||||
|
config.__retryCount = config.__retryCount || 0;
|
||||||
|
if (config.__retryCount >= config.retryCount) {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
config.__retryCount += 1;
|
||||||
|
await new Promise(resolve => setTimeout(resolve, config.retryDelay || 1000));
|
||||||
|
return request(config);
|
||||||
|
};
|
||||||
|
|
||||||
|
const logRequest = (config: AxiosRequestConfig) => {
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
console.log(`[Request] ${config.method?.toUpperCase()} ${config.url}`, {
|
||||||
|
data: config.data,
|
||||||
|
params: config.params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const logResponse = (response: AxiosResponse) => {
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
console.log(`[Response] ${response.config.url}`, response.data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export enum ErrorType {
|
||||||
|
Timeout = 'TIMEOUT',
|
||||||
|
Network = 'NETWORK',
|
||||||
|
Business = 'BUSINESS',
|
||||||
|
Auth = 'AUTH',
|
||||||
|
Server = 'SERVER'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RequestError extends Error {
|
||||||
|
type: ErrorType;
|
||||||
|
code?: number;
|
||||||
|
data?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const createRequestError = (type: ErrorType, message: string, data?: any): RequestError => {
|
||||||
|
const error = new Error(message) as RequestError;
|
||||||
|
error.type = type;
|
||||||
|
error.data = data;
|
||||||
|
return error;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RequestQueue {
|
||||||
|
private queue: Set<string> = new Set();
|
||||||
|
|
||||||
|
add(config: AxiosRequestConfig) {
|
||||||
|
const url = [config.method, config.url].join('&');
|
||||||
|
this.queue.add(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(config: AxiosRequestConfig) {
|
||||||
|
const url = [config.method, config.url].join('&');
|
||||||
|
this.queue.delete(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
size() {
|
||||||
|
return this.queue.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestQueue = new RequestQueue();
|
||||||
|
|
||||||
|
export interface CancelablePromise<T> extends Promise<T> {
|
||||||
|
cancel: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const createCancelableRequest = <T>(promise: Promise<T>, controller: AbortController): CancelablePromise<T> => {
|
||||||
|
const cancelablePromise = promise as CancelablePromise<T>;
|
||||||
|
cancelablePromise.cancel = () => controller.abort();
|
||||||
|
return cancelablePromise;
|
||||||
|
};
|
||||||
|
|
||||||
|
const debounceRequest = <T>(fn: () => Promise<T>, delay: number): (() => Promise<T>) => {
|
||||||
|
let timer: NodeJS.Timeout;
|
||||||
|
return () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (timer) clearTimeout(timer);
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
fn().then(resolve).catch(reject);
|
||||||
|
}, delay);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class RequestCache {
|
||||||
|
private cache = new Map<string, {
|
||||||
|
data: any;
|
||||||
|
timestamp: number;
|
||||||
|
ttl: number;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
set(key: string, data: any, ttl: number = 5000) {
|
||||||
|
this.cache.set(key, {
|
||||||
|
data,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
ttl
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get(key: string) {
|
||||||
|
const cached = this.cache.get(key);
|
||||||
|
if (!cached) return null;
|
||||||
|
if (Date.now() - cached.timestamp > cached.ttl) {
|
||||||
|
this.cache.delete(key);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return cached.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.cache.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RequestInterceptors {
|
||||||
|
beforeRequest?: (config: RequestOptions) => RequestOptions | Promise<RequestOptions>;
|
||||||
|
afterResponse?: (response: any) => any;
|
||||||
|
onError?: (error: any) => any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PriorityRequest {
|
||||||
|
priority: number;
|
||||||
|
request: () => Promise<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PriorityQueue {
|
||||||
|
private queue: PriorityRequest[] = [];
|
||||||
|
private processing = false;
|
||||||
|
|
||||||
|
add(request: PriorityRequest) {
|
||||||
|
this.queue.push(request);
|
||||||
|
this.queue.sort((a, b) => b.priority - a.priority);
|
||||||
|
if (!this.processing) {
|
||||||
|
this.process();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async process() {
|
||||||
|
this.processing = true;
|
||||||
|
while (this.queue.length > 0) {
|
||||||
|
const { request } = this.queue.shift()!;
|
||||||
|
await request();
|
||||||
|
}
|
||||||
|
this.processing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default http;
|
||||||
Loading…
Reference in New Issue
Block a user